diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5237d2..d5e1c7a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,51 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: branches-ignore: - 'stl-preview-head/**' - 'stl-preview-base/**' jobs: + build: + timeout-minutes: 10 + name: build + permissions: + contents: read + id-token: write + runs-on: ${{ github.repository == 'stainless-sdks/imagekit-go' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: |- + github.repository == 'stainless-sdks/imagekit-go' && + (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') + steps: + - uses: actions/checkout@v6 + + - name: Get GitHub OIDC Token + if: |- + github.repository == 'stainless-sdks/imagekit-go' && + !startsWith(github.ref, 'refs/heads/stl/') + id: github-oidc + uses: actions/github-script@v8 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Upload tarball + if: |- + github.repository == 'stainless-sdks/imagekit-go' && + !startsWith(github.ref, 'refs/heads/stl/') + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + run: ./scripts/utils/upload-artifact.sh lint: timeout-minutes: 10 name: lint diff --git a/.gitignore b/.gitignore index f7cafc9..01c321d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .prism.log +.stdy.log codegen.log Brewfile.lock.json .idea/ diff --git a/.release-please-manifest.json b/.release-please-manifest.json index bfc26f9..75ec52f 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "2.2.0" + ".": "2.3.0" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index 94357b3..0e8db84 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-13fc3d7cafdea492f62eef7c1d63424d6d9d8adbff74b9f6ca6fd3fc12a36840.yml -openapi_spec_hash: a1fe6fa48207791657a1ea2d60a6dfcc +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/imagekit-inc%2Fimagekit-63aff1629530786015da3c86131afa8a9b60545d488884b77641f1d4b89c6e9d.yml +openapi_spec_hash: 586d357bd7e5217d240a99e0d83c6d1f config_hash: 47cb702ee2cb52c58d803ae39ade9b44 diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a9b04c..99dd1f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,53 @@ # Changelog +## 2.3.0 (2026-04-06) + +Full Changelog: [v2.2.0...v2.3.0](https://github.com/imagekit-developer/imagekit-go/compare/v2.2.0...v2.3.0) + +### Features + +* **api:** add support for xCenter, yCenter, and anchorPoint in overlay URL generation ([50ef82e](https://github.com/imagekit-developer/imagekit-go/commit/50ef82eb5eb19302a7c9933166e2643c4b60b6ec)) +* **api:** dpr type update ([7b5ed76](https://github.com/imagekit-developer/imagekit-go/commit/7b5ed7649a30f369e05741ad26e87866ab369341)) +* **api:** Introduce lxc, lyc, lap parameters in overlays. ([1d33db8](https://github.com/imagekit-developer/imagekit-go/commit/1d33db8dbb8860ca132781e558ce3dab880860b2)) +* **api:** revert dpr breaking change ([4f76b02](https://github.com/imagekit-developer/imagekit-go/commit/4f76b02da01cce562522509abc4aeb9f43632227)) +* **internal:** support comma format in multipart form encoding ([e0ecf81](https://github.com/imagekit-developer/imagekit-go/commit/e0ecf8124b1c7a1f02cef55883fb139e0bbf2363)) + + +### Bug Fixes + +* allow canceling a request while it is waiting to retry ([c772a06](https://github.com/imagekit-developer/imagekit-go/commit/c772a06aa381125614083d572ce99b73b4eb3ce5)) +* **encoder:** correctly serialize NullStruct ([c8a223a](https://github.com/imagekit-developer/imagekit-go/commit/c8a223a358428b56cd5f13843928252c58acff90)) +* fix issue with unmarshaling in some cases ([c05145e](https://github.com/imagekit-developer/imagekit-go/commit/c05145eb2eced30cb2398810796c0b6a2fa81e00)) +* fix request delays for retrying to be more respectful of high requested delays ([065df63](https://github.com/imagekit-developer/imagekit-go/commit/065df633342605e2d5f69d707170c8b92e5f59fb)) +* prevent duplicate ? in query params ([1c53d0d](https://github.com/imagekit-developer/imagekit-go/commit/1c53d0da2b0a2eaa26b29b3fa6b69dc84d78a8be)) +* **types:** generate shared enum types that are not referenced by other schemas ([420472d](https://github.com/imagekit-developer/imagekit-go/commit/420472d6e58c1626a7a15fa0c81cfbe02539c2d0)) + + +### Chores + +* **ci:** add build step ([950faa7](https://github.com/imagekit-developer/imagekit-go/commit/950faa70ba325a3af7e2149618d1690d681888a1)) +* **ci:** skip lint on metadata-only changes ([cb58aa5](https://github.com/imagekit-developer/imagekit-go/commit/cb58aa516481e088ef0924c1d2e8979df33800aa)) +* **ci:** skip uploading artifacts on stainless-internal branches ([1fedd9f](https://github.com/imagekit-developer/imagekit-go/commit/1fedd9f85df8d3c231fb7eb7e342ef98a2fe3acc)) +* **ci:** support opting out of skipping builds on metadata-only commits ([9781c64](https://github.com/imagekit-developer/imagekit-go/commit/9781c64025356760a3b067d0f13c897282747997)) +* **client:** fix multipart serialisation of Default() fields ([facb97a](https://github.com/imagekit-developer/imagekit-go/commit/facb97a34c051ca7f0b5ce1c18fca7eddf94b68e)) +* **internal:** codegen related update ([a4bb374](https://github.com/imagekit-developer/imagekit-go/commit/a4bb374e09dc89d66cc143dc3b6bb1f315e0e4cb)) +* **internal:** codegen related update ([255a031](https://github.com/imagekit-developer/imagekit-go/commit/255a0313de39110cdedc4002d451bdc39e3bc308)) +* **internal:** codegen related update ([e1e4755](https://github.com/imagekit-developer/imagekit-go/commit/e1e47559733779920f899cb665b244e431702668)) +* **internal:** codegen related update ([5071176](https://github.com/imagekit-developer/imagekit-go/commit/50711763c0f3bee01b36ab00500db61aa371415b)) +* **internal:** minor cleanup ([bba2f4a](https://github.com/imagekit-developer/imagekit-go/commit/bba2f4a012b76ed18936d5659db28505d88cf694)) +* **internal:** move custom custom `json` tags to `api` ([4609e1f](https://github.com/imagekit-developer/imagekit-go/commit/4609e1fd02735cc92d442ab6c6360429b5a8318d)) +* **internal:** remove mock server code ([ab007f7](https://github.com/imagekit-developer/imagekit-go/commit/ab007f7fa428ff639b7c1177976d76b4c66eb5f5)) +* **internal:** support default value struct tag ([86a3f7c](https://github.com/imagekit-developer/imagekit-go/commit/86a3f7cc8bce7c25b59720b35dfe590b974933eb)) +* **internal:** tweak CI branches ([28a816d](https://github.com/imagekit-developer/imagekit-go/commit/28a816d34c0bb30be0a550ade3fc7e3a848c98bf)) +* **internal:** update gitignore ([bbc7450](https://github.com/imagekit-developer/imagekit-go/commit/bbc745035b8765ad93a60ab91114135d1343e1d0)) +* **internal:** use explicit returns ([3d59762](https://github.com/imagekit-developer/imagekit-go/commit/3d59762abc0b08d20e1d3aa2f10e1e46b8e605b0)) +* **internal:** use explicit returns in more places ([93dfb11](https://github.com/imagekit-developer/imagekit-go/commit/93dfb117b673e0fbb123d47862bd48f7e685bfdd)) +* remove unnecessary error check for url parsing ([7517de5](https://github.com/imagekit-developer/imagekit-go/commit/7517de5c74a9c6cc7bab2ed0fa6c48278558d1b5)) +* **tests:** update webhook tests ([f3ef31e](https://github.com/imagekit-developer/imagekit-go/commit/f3ef31e396305fb69fa7905821fd2e94258f3b18)) +* update docs for api:"required" ([d5de86f](https://github.com/imagekit-developer/imagekit-go/commit/d5de86f78052cefc4c28da6049f66980d7f79112)) +* update mock server docs ([1ba9e87](https://github.com/imagekit-developer/imagekit-go/commit/1ba9e87f6b30e3992999808434dd39298de4d0a0)) +* update placeholder string ([a783267](https://github.com/imagekit-developer/imagekit-go/commit/a7832673f2d1d19e5c1d87b2ab3ad3b152288f73)) + ## 2.2.0 (2026-02-02) Full Changelog: [v2.1.1...v2.2.0](https://github.com/imagekit-developer/imagekit-go/compare/v2.1.1...v2.2.0) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0635957..00f7743 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -46,13 +46,6 @@ $ go mod edit -replace github.com/imagekit-developer/imagekit-go=/path/to/imagek ## Running tests -Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. - -```sh -# you will need npm installed -$ npx prism mock path/to/your/openapi.yml -``` - ```sh $ ./scripts/test ``` diff --git a/README.md b/README.md index ffc95e0..b41c73f 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.2.0' +go get -u 'github.com/imagekit-developer/imagekit-go/v2@v2.3.0' ``` @@ -112,7 +112,7 @@ func main() { The imagekit library uses the [`omitzero`](https://tip.golang.org/doc/go1.24#encodingjsonpkgencodingjson) semantics from the Go 1.24+ `encoding/json` release for request fields. -Required primitive fields (`int64`, `string`, etc.) feature the tag \`json:"...,required"\`. These +Required primitive fields (`int64`, `string`, etc.) feature the tag \`api:"required"\`. These fields are always serialized, even their zero values. Optional primitive types are wrapped in a `param.Opt[T]`. These fields can be set with the provided constructors, `imagekit.String(string)`, `imagekit.Int(int64)`, etc. diff --git a/accountorigin.go b/accountorigin.go index 52888b2..e3db111 100644 --- a/accountorigin.go +++ b/accountorigin.go @@ -44,7 +44,7 @@ func (r *AccountOriginService) New(ctx context.Context, body AccountOriginNewPar opts = slices.Concat(r.Options, opts) path := "v1/accounts/origins" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // **Note:** This API is currently in beta. @@ -53,11 +53,11 @@ func (r *AccountOriginService) Update(ctx context.Context, id string, body Accou opts = slices.Concat(r.Options, opts) if id == "" { err = errors.New("missing required id parameter") - return + return nil, err } path := fmt.Sprintf("v1/accounts/origins/%s", id) err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, body, &res, opts...) - return + return res, err } // **Note:** This API is currently in beta. @@ -66,7 +66,7 @@ func (r *AccountOriginService) List(ctx context.Context, opts ...option.RequestO opts = slices.Concat(r.Options, opts) path := "v1/accounts/origins" err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + return res, err } // **Note:** This API is currently in beta. @@ -77,11 +77,11 @@ func (r *AccountOriginService) Delete(ctx context.Context, id string, opts ...op opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") - return + return err } path := fmt.Sprintf("v1/accounts/origins/%s", id) err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, nil, opts...) - return + return err } // **Note:** This API is currently in beta. @@ -90,11 +90,11 @@ func (r *AccountOriginService) Get(ctx context.Context, id string, opts ...optio opts = slices.Concat(r.Options, opts) if id == "" { err = errors.New("missing required id parameter") - return + return nil, err } path := fmt.Sprintf("v1/accounts/origins/%s", id) err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + return res, err } func OriginRequestParamOfWebFolder(baseURL string, name string) OriginRequestUnionParam { @@ -425,13 +425,13 @@ func init() { // The properties AccessKey, Bucket, Name, SecretKey, Type are required. type OriginRequestS3Param struct { // Access key for the bucket. - AccessKey string `json:"accessKey,required"` + AccessKey string `json:"accessKey" api:"required"` // S3 bucket name. - Bucket string `json:"bucket,required"` + Bucket string `json:"bucket" api:"required"` // Display name of the origin. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // Secret key for the bucket. - SecretKey string `json:"secretKey,required"` + SecretKey string `json:"secretKey" api:"required"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader param.Opt[string] `json:"baseUrlForCanonicalHeader,omitzero" format:"uri"` // Whether to send a Canonical header. @@ -439,7 +439,7 @@ type OriginRequestS3Param struct { // Path prefix inside the bucket. Prefix param.Opt[string] `json:"prefix,omitzero"` // This field can be elided, and will marshal its zero value as "S3". - Type constant.S3 `json:"type,required"` + Type constant.S3 `json:"type" default:"S3"` paramObj } @@ -454,15 +454,15 @@ func (r *OriginRequestS3Param) UnmarshalJSON(data []byte) error { // The properties AccessKey, Bucket, Endpoint, Name, SecretKey, Type are required. type OriginRequestS3CompatibleParam struct { // Access key for the bucket. - AccessKey string `json:"accessKey,required"` + AccessKey string `json:"accessKey" api:"required"` // S3 bucket name. - Bucket string `json:"bucket,required"` + Bucket string `json:"bucket" api:"required"` // Custom S3-compatible endpoint. - Endpoint string `json:"endpoint,required" format:"uri"` + Endpoint string `json:"endpoint" api:"required" format:"uri"` // Display name of the origin. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // Secret key for the bucket. - SecretKey string `json:"secretKey,required"` + SecretKey string `json:"secretKey" api:"required"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader param.Opt[string] `json:"baseUrlForCanonicalHeader,omitzero" format:"uri"` // Whether to send a Canonical header. @@ -472,7 +472,7 @@ type OriginRequestS3CompatibleParam struct { // Use path-style S3 URLs? S3ForcePathStyle param.Opt[bool] `json:"s3ForcePathStyle,omitzero"` // This field can be elided, and will marshal its zero value as "S3_COMPATIBLE". - Type constant.S3Compatible `json:"type,required"` + Type constant.S3Compatible `json:"type" default:"S3_COMPATIBLE"` paramObj } @@ -487,13 +487,13 @@ func (r *OriginRequestS3CompatibleParam) UnmarshalJSON(data []byte) error { // The properties AccessKey, Bucket, Name, SecretKey, Type are required. type OriginRequestCloudinaryBackupParam struct { // Access key for the bucket. - AccessKey string `json:"accessKey,required"` + AccessKey string `json:"accessKey" api:"required"` // S3 bucket name. - Bucket string `json:"bucket,required"` + Bucket string `json:"bucket" api:"required"` // Display name of the origin. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // Secret key for the bucket. - SecretKey string `json:"secretKey,required"` + SecretKey string `json:"secretKey" api:"required"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader param.Opt[string] `json:"baseUrlForCanonicalHeader,omitzero" format:"uri"` // Whether to send a Canonical header. @@ -502,7 +502,7 @@ type OriginRequestCloudinaryBackupParam struct { Prefix param.Opt[string] `json:"prefix,omitzero"` // This field can be elided, and will marshal its zero value as // "CLOUDINARY_BACKUP". - Type constant.CloudinaryBackup `json:"type,required"` + Type constant.CloudinaryBackup `json:"type" default:"CLOUDINARY_BACKUP"` paramObj } @@ -517,9 +517,9 @@ func (r *OriginRequestCloudinaryBackupParam) UnmarshalJSON(data []byte) error { // The properties BaseURL, Name, Type are required. type OriginRequestWebFolderParam struct { // Root URL for the web folder origin. - BaseURL string `json:"baseUrl,required" format:"uri"` + BaseURL string `json:"baseUrl" api:"required" format:"uri"` // Display name of the origin. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader param.Opt[string] `json:"baseUrlForCanonicalHeader,omitzero" format:"uri"` // Forward the Host header to origin? @@ -527,7 +527,7 @@ type OriginRequestWebFolderParam struct { // Whether to send a Canonical header. IncludeCanonicalHeader param.Opt[bool] `json:"includeCanonicalHeader,omitzero"` // This field can be elided, and will marshal its zero value as "WEB_FOLDER". - Type constant.WebFolder `json:"type,required"` + Type constant.WebFolder `json:"type" default:"WEB_FOLDER"` paramObj } @@ -542,13 +542,13 @@ func (r *OriginRequestWebFolderParam) UnmarshalJSON(data []byte) error { // The properties Name, Type are required. type OriginRequestWebProxyParam struct { // Display name of the origin. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader param.Opt[string] `json:"baseUrlForCanonicalHeader,omitzero" format:"uri"` // Whether to send a Canonical header. IncludeCanonicalHeader param.Opt[bool] `json:"includeCanonicalHeader,omitzero"` // This field can be elided, and will marshal its zero value as "WEB_PROXY". - Type constant.WebProxy `json:"type,required"` + Type constant.WebProxy `json:"type" default:"WEB_PROXY"` paramObj } @@ -562,18 +562,18 @@ func (r *OriginRequestWebProxyParam) UnmarshalJSON(data []byte) error { // The properties Bucket, ClientEmail, Name, PrivateKey, Type are required. type OriginRequestGcsParam struct { - Bucket string `json:"bucket,required"` - ClientEmail string `json:"clientEmail,required" format:"email"` + Bucket string `json:"bucket" api:"required"` + ClientEmail string `json:"clientEmail" api:"required" format:"email"` // Display name of the origin. - Name string `json:"name,required"` - PrivateKey string `json:"privateKey,required"` + Name string `json:"name" api:"required"` + PrivateKey string `json:"privateKey" api:"required"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader param.Opt[string] `json:"baseUrlForCanonicalHeader,omitzero" format:"uri"` // Whether to send a Canonical header. IncludeCanonicalHeader param.Opt[bool] `json:"includeCanonicalHeader,omitzero"` Prefix param.Opt[string] `json:"prefix,omitzero"` // This field can be elided, and will marshal its zero value as "GCS". - Type constant.Gcs `json:"type,required"` + Type constant.Gcs `json:"type" default:"GCS"` paramObj } @@ -587,18 +587,18 @@ func (r *OriginRequestGcsParam) UnmarshalJSON(data []byte) error { // The properties AccountName, Container, Name, SasToken, Type are required. type OriginRequestAzureBlobParam struct { - AccountName string `json:"accountName,required"` - Container string `json:"container,required"` + AccountName string `json:"accountName" api:"required"` + Container string `json:"container" api:"required"` // Display name of the origin. - Name string `json:"name,required"` - SasToken string `json:"sasToken,required"` + Name string `json:"name" api:"required"` + SasToken string `json:"sasToken" api:"required"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader param.Opt[string] `json:"baseUrlForCanonicalHeader,omitzero" format:"uri"` // Whether to send a Canonical header. IncludeCanonicalHeader param.Opt[bool] `json:"includeCanonicalHeader,omitzero"` Prefix param.Opt[string] `json:"prefix,omitzero"` // This field can be elided, and will marshal its zero value as "AZURE_BLOB". - Type constant.AzureBlob `json:"type,required"` + Type constant.AzureBlob `json:"type" default:"AZURE_BLOB"` paramObj } @@ -614,23 +614,23 @@ func (r *OriginRequestAzureBlobParam) UnmarshalJSON(data []byte) error { // are required. type OriginRequestAkeneoPimParam struct { // Akeneo instance base URL. - BaseURL string `json:"baseUrl,required" format:"uri"` + BaseURL string `json:"baseUrl" api:"required" format:"uri"` // Akeneo API client ID. - ClientID string `json:"clientId,required"` + ClientID string `json:"clientId" api:"required"` // Akeneo API client secret. - ClientSecret string `json:"clientSecret,required"` + ClientSecret string `json:"clientSecret" api:"required"` // Display name of the origin. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // Akeneo API password. - Password string `json:"password,required"` + Password string `json:"password" api:"required"` // Akeneo API username. - Username string `json:"username,required"` + Username string `json:"username" api:"required"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader param.Opt[string] `json:"baseUrlForCanonicalHeader,omitzero" format:"uri"` // Whether to send a Canonical header. IncludeCanonicalHeader param.Opt[bool] `json:"includeCanonicalHeader,omitzero"` // This field can be elided, and will marshal its zero value as "AKENEO_PIM". - Type constant.AkeneoPim `json:"type,required"` + Type constant.AkeneoPim `json:"type" default:"AKENEO_PIM"` paramObj } @@ -794,16 +794,16 @@ func (r *OriginResponseUnion) UnmarshalJSON(data []byte) error { type OriginResponseS3 struct { // Unique identifier for the origin. This is generated by ImageKit when you create // a new origin. - ID string `json:"id,required"` + ID string `json:"id" api:"required"` // S3 bucket name. - Bucket string `json:"bucket,required"` + Bucket string `json:"bucket" api:"required"` // Whether to send a Canonical header. - IncludeCanonicalHeader bool `json:"includeCanonicalHeader,required"` + IncludeCanonicalHeader bool `json:"includeCanonicalHeader" api:"required"` // Display name of the origin. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // Path prefix inside the bucket. - Prefix string `json:"prefix,required"` - Type constant.S3 `json:"type,required"` + Prefix string `json:"prefix" api:"required"` + Type constant.S3 `json:"type" default:"S3"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader string `json:"baseUrlForCanonicalHeader" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -829,20 +829,20 @@ func (r *OriginResponseS3) UnmarshalJSON(data []byte) error { type OriginResponseS3Compatible struct { // Unique identifier for the origin. This is generated by ImageKit when you create // a new origin. - ID string `json:"id,required"` + ID string `json:"id" api:"required"` // S3 bucket name. - Bucket string `json:"bucket,required"` + Bucket string `json:"bucket" api:"required"` // Custom S3-compatible endpoint. - Endpoint string `json:"endpoint,required" format:"uri"` + Endpoint string `json:"endpoint" api:"required" format:"uri"` // Whether to send a Canonical header. - IncludeCanonicalHeader bool `json:"includeCanonicalHeader,required"` + IncludeCanonicalHeader bool `json:"includeCanonicalHeader" api:"required"` // Display name of the origin. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // Path prefix inside the bucket. - Prefix string `json:"prefix,required"` + Prefix string `json:"prefix" api:"required"` // Use path-style S3 URLs? - S3ForcePathStyle bool `json:"s3ForcePathStyle,required"` - Type constant.S3Compatible `json:"type,required"` + S3ForcePathStyle bool `json:"s3ForcePathStyle" api:"required"` + Type constant.S3Compatible `json:"type" default:"S3_COMPATIBLE"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader string `json:"baseUrlForCanonicalHeader" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -870,16 +870,16 @@ func (r *OriginResponseS3Compatible) UnmarshalJSON(data []byte) error { type OriginResponseCloudinaryBackup struct { // Unique identifier for the origin. This is generated by ImageKit when you create // a new origin. - ID string `json:"id,required"` + ID string `json:"id" api:"required"` // S3 bucket name. - Bucket string `json:"bucket,required"` + Bucket string `json:"bucket" api:"required"` // Whether to send a Canonical header. - IncludeCanonicalHeader bool `json:"includeCanonicalHeader,required"` + IncludeCanonicalHeader bool `json:"includeCanonicalHeader" api:"required"` // Display name of the origin. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // Path prefix inside the bucket. - Prefix string `json:"prefix,required"` - Type constant.CloudinaryBackup `json:"type,required"` + Prefix string `json:"prefix" api:"required"` + Type constant.CloudinaryBackup `json:"type" default:"CLOUDINARY_BACKUP"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader string `json:"baseUrlForCanonicalHeader" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -905,16 +905,16 @@ func (r *OriginResponseCloudinaryBackup) UnmarshalJSON(data []byte) error { type OriginResponseWebFolder struct { // Unique identifier for the origin. This is generated by ImageKit when you create // a new origin. - ID string `json:"id,required"` + ID string `json:"id" api:"required"` // Root URL for the web folder origin. - BaseURL string `json:"baseUrl,required" format:"uri"` + BaseURL string `json:"baseUrl" api:"required" format:"uri"` // Forward the Host header to origin? - ForwardHostHeaderToOrigin bool `json:"forwardHostHeaderToOrigin,required"` + ForwardHostHeaderToOrigin bool `json:"forwardHostHeaderToOrigin" api:"required"` // Whether to send a Canonical header. - IncludeCanonicalHeader bool `json:"includeCanonicalHeader,required"` + IncludeCanonicalHeader bool `json:"includeCanonicalHeader" api:"required"` // Display name of the origin. - Name string `json:"name,required"` - Type constant.WebFolder `json:"type,required"` + Name string `json:"name" api:"required"` + Type constant.WebFolder `json:"type" default:"WEB_FOLDER"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader string `json:"baseUrlForCanonicalHeader" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -940,12 +940,12 @@ func (r *OriginResponseWebFolder) UnmarshalJSON(data []byte) error { type OriginResponseWebProxy struct { // Unique identifier for the origin. This is generated by ImageKit when you create // a new origin. - ID string `json:"id,required"` + ID string `json:"id" api:"required"` // Whether to send a Canonical header. - IncludeCanonicalHeader bool `json:"includeCanonicalHeader,required"` + IncludeCanonicalHeader bool `json:"includeCanonicalHeader" api:"required"` // Display name of the origin. - Name string `json:"name,required"` - Type constant.WebProxy `json:"type,required"` + Name string `json:"name" api:"required"` + Type constant.WebProxy `json:"type" default:"WEB_PROXY"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader string `json:"baseUrlForCanonicalHeader" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -969,15 +969,15 @@ func (r *OriginResponseWebProxy) UnmarshalJSON(data []byte) error { type OriginResponseGcs struct { // Unique identifier for the origin. This is generated by ImageKit when you create // a new origin. - ID string `json:"id,required"` - Bucket string `json:"bucket,required"` - ClientEmail string `json:"clientEmail,required" format:"email"` + ID string `json:"id" api:"required"` + Bucket string `json:"bucket" api:"required"` + ClientEmail string `json:"clientEmail" api:"required" format:"email"` // Whether to send a Canonical header. - IncludeCanonicalHeader bool `json:"includeCanonicalHeader,required"` + IncludeCanonicalHeader bool `json:"includeCanonicalHeader" api:"required"` // Display name of the origin. - Name string `json:"name,required"` - Prefix string `json:"prefix,required"` - Type constant.Gcs `json:"type,required"` + Name string `json:"name" api:"required"` + Prefix string `json:"prefix" api:"required"` + Type constant.Gcs `json:"type" default:"GCS"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader string `json:"baseUrlForCanonicalHeader" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -1004,15 +1004,15 @@ func (r *OriginResponseGcs) UnmarshalJSON(data []byte) error { type OriginResponseAzureBlob struct { // Unique identifier for the origin. This is generated by ImageKit when you create // a new origin. - ID string `json:"id,required"` - AccountName string `json:"accountName,required"` - Container string `json:"container,required"` + ID string `json:"id" api:"required"` + AccountName string `json:"accountName" api:"required"` + Container string `json:"container" api:"required"` // Whether to send a Canonical header. - IncludeCanonicalHeader bool `json:"includeCanonicalHeader,required"` + IncludeCanonicalHeader bool `json:"includeCanonicalHeader" api:"required"` // Display name of the origin. - Name string `json:"name,required"` - Prefix string `json:"prefix,required"` - Type constant.AzureBlob `json:"type,required"` + Name string `json:"name" api:"required"` + Prefix string `json:"prefix" api:"required"` + Type constant.AzureBlob `json:"type" default:"AZURE_BLOB"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader string `json:"baseUrlForCanonicalHeader" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -1039,14 +1039,14 @@ func (r *OriginResponseAzureBlob) UnmarshalJSON(data []byte) error { type OriginResponseAkeneoPim struct { // Unique identifier for the origin. This is generated by ImageKit when you create // a new origin. - ID string `json:"id,required"` + ID string `json:"id" api:"required"` // Akeneo instance base URL. - BaseURL string `json:"baseUrl,required" format:"uri"` + BaseURL string `json:"baseUrl" api:"required" format:"uri"` // Whether to send a Canonical header. - IncludeCanonicalHeader bool `json:"includeCanonicalHeader,required"` + IncludeCanonicalHeader bool `json:"includeCanonicalHeader" api:"required"` // Display name of the origin. - Name string `json:"name,required"` - Type constant.AkeneoPim `json:"type,required"` + Name string `json:"name" api:"required"` + Type constant.AkeneoPim `json:"type" default:"AKENEO_PIM"` // URL used in the Canonical header (if enabled). BaseURLForCanonicalHeader string `json:"baseUrlForCanonicalHeader" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -1078,7 +1078,7 @@ func (r AccountOriginNewParams) MarshalJSON() (data []byte, err error) { return shimjson.Marshal(r.OriginRequest) } func (r *AccountOriginNewParams) UnmarshalJSON(data []byte) error { - return json.Unmarshal(data, &r.OriginRequest) + return apijson.UnmarshalRoot(data, r) } type AccountOriginUpdateParams struct { @@ -1091,5 +1091,5 @@ func (r AccountOriginUpdateParams) MarshalJSON() (data []byte, err error) { return shimjson.Marshal(r.OriginRequest) } func (r *AccountOriginUpdateParams) UnmarshalJSON(data []byte) error { - return json.Unmarshal(data, &r.OriginRequest) + return apijson.UnmarshalRoot(data, r) } diff --git a/accountorigin_test.go b/accountorigin_test.go index 350726b..3161145 100644 --- a/accountorigin_test.go +++ b/accountorigin_test.go @@ -14,7 +14,7 @@ import ( ) func TestAccountOriginNewWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -50,7 +50,7 @@ func TestAccountOriginNewWithOptionalParams(t *testing.T) { } func TestAccountOriginUpdateWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -90,7 +90,7 @@ func TestAccountOriginUpdateWithOptionalParams(t *testing.T) { } func TestAccountOriginList(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -114,7 +114,7 @@ func TestAccountOriginList(t *testing.T) { } func TestAccountOriginDelete(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -138,7 +138,7 @@ func TestAccountOriginDelete(t *testing.T) { } func TestAccountOriginGet(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL diff --git a/accounturlendpoint.go b/accounturlendpoint.go index dbd0224..35d40b7 100644 --- a/accounturlendpoint.go +++ b/accounturlendpoint.go @@ -44,7 +44,7 @@ func (r *AccountURLEndpointService) New(ctx context.Context, body AccountURLEndp opts = slices.Concat(r.Options, opts) path := "v1/accounts/url-endpoints" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // **Note:** This API is currently in beta. @@ -53,11 +53,11 @@ func (r *AccountURLEndpointService) Update(ctx context.Context, id string, body opts = slices.Concat(r.Options, opts) if id == "" { err = errors.New("missing required id parameter") - return + return nil, err } path := fmt.Sprintf("v1/accounts/url-endpoints/%s", id) err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, body, &res, opts...) - return + return res, err } // **Note:** This API is currently in beta. @@ -67,7 +67,7 @@ func (r *AccountURLEndpointService) List(ctx context.Context, opts ...option.Req opts = slices.Concat(r.Options, opts) path := "v1/accounts/url-endpoints" err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + return res, err } // **Note:** This API is currently in beta. @@ -78,11 +78,11 @@ func (r *AccountURLEndpointService) Delete(ctx context.Context, id string, opts opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") - return + return err } path := fmt.Sprintf("v1/accounts/url-endpoints/%s", id) err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, nil, opts...) - return + return err } // **Note:** This API is currently in beta. @@ -91,11 +91,11 @@ func (r *AccountURLEndpointService) Get(ctx context.Context, id string, opts ... opts = slices.Concat(r.Options, opts) if id == "" { err = errors.New("missing required id parameter") - return + return nil, err } path := fmt.Sprintf("v1/accounts/url-endpoints/%s", id) err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + return res, err } // Schema for URL endpoint resource. @@ -103,7 +103,7 @@ func (r *AccountURLEndpointService) Get(ctx context.Context, id string, opts ... // The property Description is required. type URLEndpointRequestParam struct { // Description of the URL endpoint. - Description string `json:"description,required"` + Description string `json:"description" api:"required"` // Path segment appended to your base URL to form the endpoint (letters, digits, // and hyphens only — or empty for the default endpoint). URLPrefix param.Opt[string] `json:"urlPrefix,omitzero"` @@ -186,7 +186,7 @@ type URLEndpointRequestURLRewriterCloudinaryParam struct { // Whether to preserve `/` in the rewritten URL. PreserveAssetDeliveryTypes param.Opt[bool] `json:"preserveAssetDeliveryTypes,omitzero"` // This field can be elided, and will marshal its zero value as "CLOUDINARY". - Type constant.Cloudinary `json:"type,required"` + Type constant.Cloudinary `json:"type" default:"CLOUDINARY"` paramObj } @@ -207,7 +207,7 @@ func NewURLEndpointRequestURLRewriterImgixParam() URLEndpointRequestURLRewriterI // This struct has a constant value, construct it with // [NewURLEndpointRequestURLRewriterImgixParam]. type URLEndpointRequestURLRewriterImgixParam struct { - Type constant.Imgix `json:"type,required"` + Type constant.Imgix `json:"type" default:"IMGIX"` paramObj } @@ -228,7 +228,7 @@ func NewURLEndpointRequestURLRewriterAkamaiParam() URLEndpointRequestURLRewriter // This struct has a constant value, construct it with // [NewURLEndpointRequestURLRewriterAkamaiParam]. type URLEndpointRequestURLRewriterAkamaiParam struct { - Type constant.Akamai `json:"type,required"` + Type constant.Akamai `json:"type" default:"AKAMAI"` paramObj } @@ -245,16 +245,16 @@ type URLEndpointResponse struct { // Unique identifier for the URL-endpoint. This is generated by ImageKit when you // create a new URL-endpoint. For the default URL-endpoint, this is always // `default`. - ID string `json:"id,required"` + ID string `json:"id" api:"required"` // Description of the URL endpoint. - Description string `json:"description,required"` + Description string `json:"description" api:"required"` // Ordered list of origin IDs to try when the file isn’t in the Media Library; // ImageKit checks them in the sequence provided. Origin must be created before it // can be used in a URL endpoint. - Origins []string `json:"origins,required"` + Origins []string `json:"origins" api:"required"` // Path segment appended to your base URL to form the endpoint (letters, digits, // and hyphens only — or empty for the default endpoint). - URLPrefix string `json:"urlPrefix,required"` + URLPrefix string `json:"urlPrefix" api:"required"` // Configuration for third-party URL rewriting. URLRewriter URLEndpointResponseURLRewriterUnion `json:"urlRewriter"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -351,8 +351,8 @@ func (r *URLEndpointResponseURLRewriterUnion) UnmarshalJSON(data []byte) error { type URLEndpointResponseURLRewriterCloudinary struct { // Whether to preserve `/` in the rewritten URL. - PreserveAssetDeliveryTypes bool `json:"preserveAssetDeliveryTypes,required"` - Type constant.Cloudinary `json:"type,required"` + PreserveAssetDeliveryTypes bool `json:"preserveAssetDeliveryTypes" api:"required"` + Type constant.Cloudinary `json:"type" default:"CLOUDINARY"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { PreserveAssetDeliveryTypes respjson.Field @@ -369,7 +369,7 @@ func (r *URLEndpointResponseURLRewriterCloudinary) UnmarshalJSON(data []byte) er } type URLEndpointResponseURLRewriterImgix struct { - Type constant.Imgix `json:"type,required"` + Type constant.Imgix `json:"type" default:"IMGIX"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Type respjson.Field @@ -385,7 +385,7 @@ func (r *URLEndpointResponseURLRewriterImgix) UnmarshalJSON(data []byte) error { } type URLEndpointResponseURLRewriterAkamai struct { - Type constant.Akamai `json:"type,required"` + Type constant.Akamai `json:"type" default:"AKAMAI"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Type respjson.Field @@ -410,7 +410,7 @@ func (r AccountURLEndpointNewParams) MarshalJSON() (data []byte, err error) { return shimjson.Marshal(r.URLEndpointRequest) } func (r *AccountURLEndpointNewParams) UnmarshalJSON(data []byte) error { - return json.Unmarshal(data, &r.URLEndpointRequest) + return apijson.UnmarshalRoot(data, r) } type AccountURLEndpointUpdateParams struct { @@ -423,5 +423,5 @@ func (r AccountURLEndpointUpdateParams) MarshalJSON() (data []byte, err error) { return shimjson.Marshal(r.URLEndpointRequest) } func (r *AccountURLEndpointUpdateParams) UnmarshalJSON(data []byte) error { - return json.Unmarshal(data, &r.URLEndpointRequest) + return apijson.UnmarshalRoot(data, r) } diff --git a/accounturlendpoint_test.go b/accounturlendpoint_test.go index 06c9c66..716ef33 100644 --- a/accounturlendpoint_test.go +++ b/accounturlendpoint_test.go @@ -14,7 +14,7 @@ import ( ) func TestAccountURLEndpointNewWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -49,7 +49,7 @@ func TestAccountURLEndpointNewWithOptionalParams(t *testing.T) { } func TestAccountURLEndpointUpdateWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -88,7 +88,7 @@ func TestAccountURLEndpointUpdateWithOptionalParams(t *testing.T) { } func TestAccountURLEndpointList(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -112,7 +112,7 @@ func TestAccountURLEndpointList(t *testing.T) { } func TestAccountURLEndpointDelete(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -136,7 +136,7 @@ func TestAccountURLEndpointDelete(t *testing.T) { } func TestAccountURLEndpointGet(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL diff --git a/accountusage.go b/accountusage.go index dadef4a..9fea667 100644 --- a/accountusage.go +++ b/accountusage.go @@ -43,7 +43,7 @@ func (r *AccountUsageService) Get(ctx context.Context, query AccountUsageGetPara opts = slices.Concat(r.Options, opts) path := "v1/accounts/usage" err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...) - return + return res, err } type AccountUsageGetResponse struct { @@ -78,10 +78,10 @@ func (r *AccountUsageGetResponse) UnmarshalJSON(data []byte) error { type AccountUsageGetParams struct { // Specify a `endDate` in `YYYY-MM-DD` format. It should be after the `startDate`. // The difference between `startDate` and `endDate` should be less than 90 days. - EndDate time.Time `query:"endDate,required" format:"date" json:"-"` + EndDate time.Time `query:"endDate" api:"required" format:"date" json:"-"` // Specify a `startDate` in `YYYY-MM-DD` format. It should be before the `endDate`. // The difference between `startDate` and `endDate` should be less than 90 days. - StartDate time.Time `query:"startDate,required" format:"date" json:"-"` + StartDate time.Time `query:"startDate" api:"required" format:"date" json:"-"` paramObj } diff --git a/accountusage_test.go b/accountusage_test.go index a206f36..dcfd282 100644 --- a/accountusage_test.go +++ b/accountusage_test.go @@ -15,7 +15,7 @@ import ( ) func TestAccountUsageGet(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL diff --git a/aliases.go b/aliases.go index a960812..9368547 100644 --- a/aliases.go +++ b/aliases.go @@ -370,8 +370,43 @@ type OverlayUnionParam = shared.OverlayUnionParam // This is an alias to an internal type. type OverlayPositionParam = shared.OverlayPositionParam -// Specifies the position of the overlay relative to the parent image or video. -// Maps to `lfo` in the URL. +// Sets the anchor point on the base asset from which the overlay offset is +// calculated. The default value is `top_left`. Maps to `lap` in the URL. Can only +// be used with one or more of `x`, `y`, `xCenter`, or `yCenter`. +// +// This is an alias to an internal type. +type OverlayPositionAnchorPoint = shared.OverlayPositionAnchorPoint + +// Equals "top" +const OverlayPositionAnchorPointTop = shared.OverlayPositionAnchorPointTop + +// Equals "left" +const OverlayPositionAnchorPointLeft = shared.OverlayPositionAnchorPointLeft + +// Equals "right" +const OverlayPositionAnchorPointRight = shared.OverlayPositionAnchorPointRight + +// Equals "bottom" +const OverlayPositionAnchorPointBottom = shared.OverlayPositionAnchorPointBottom + +// Equals "top_left" +const OverlayPositionAnchorPointTopLeft = shared.OverlayPositionAnchorPointTopLeft + +// Equals "top_right" +const OverlayPositionAnchorPointTopRight = shared.OverlayPositionAnchorPointTopRight + +// Equals "bottom_left" +const OverlayPositionAnchorPointBottomLeft = shared.OverlayPositionAnchorPointBottomLeft + +// Equals "bottom_right" +const OverlayPositionAnchorPointBottomRight = shared.OverlayPositionAnchorPointBottomRight + +// Equals "center" +const OverlayPositionAnchorPointCenter = shared.OverlayPositionAnchorPointCenter + +// Specifies the position of the overlay relative to the parent image or video. If +// one or more of `x`, `y`, `xCenter`, or `yCenter` parameters are specified, this +// parameter is ignored. Maps to `lfo` in the URL. // // This is an alias to an internal type. type OverlayPositionFocus = shared.OverlayPositionFocus @@ -412,6 +447,15 @@ const OverlayPositionFocusBottomRight = shared.OverlayPositionFocusBottomRight // This is an alias to an internal type. type OverlayPositionXUnionParam = shared.OverlayPositionXUnionParam +// Specifies the x-coordinate on the base asset where the overlay's center will be +// positioned. It also accepts arithmetic expressions such as `bw_mul_0.4` or +// `bw_sub_cw`. Maps to `lxc` in the URL. Cannot be used together with `x`, but can +// be used with `y`. Learn about +// [Arithmetic expressions](https://imagekit.io/docs/arithmetic-expressions-in-transformations). +// +// This is an alias to an internal type. +type OverlayPositionXCenterUnionParam = shared.OverlayPositionXCenterUnionParam + // Specifies the y-coordinate of the top-left corner of the base asset where the // overlay's top-left corner will be positioned. It also accepts arithmetic // expressions such as `bh_mul_0.4` or `bh_sub_ch`. Maps to `ly` in the URL. Learn @@ -421,6 +465,15 @@ type OverlayPositionXUnionParam = shared.OverlayPositionXUnionParam // This is an alias to an internal type. type OverlayPositionYUnionParam = shared.OverlayPositionYUnionParam +// Specifies the y-coordinate on the base asset where the overlay's center will be +// positioned. It also accepts arithmetic expressions such as `bh_mul_0.4` or +// `bh_sub_ch`. Maps to `lyc` in the URL. Cannot be used together with `y`, but can +// be used with `x`. Learn about +// [Arithmetic expressions](https://imagekit.io/docs/arithmetic-expressions-in-transformations). +// +// This is an alias to an internal type. +type OverlayPositionYCenterUnionParam = shared.OverlayPositionYCenterUnionParam + // This is an alias to an internal type. type OverlayTimingParam = shared.OverlayTimingParam diff --git a/api.md b/api.md index 30966e3..ef24b6d 100644 --- a/api.md +++ b/api.md @@ -26,6 +26,8 @@ - shared.ExtensionConfigUnion - shared.SavedExtension +- shared.StreamingResolution +- shared.TransformationPosition # CustomMetadataFields diff --git a/asset.go b/asset.go index ff95c4e..e5deffb 100644 --- a/asset.go +++ b/asset.go @@ -45,7 +45,7 @@ func (r *AssetService) List(ctx context.Context, query AssetListParams, opts ... opts = slices.Concat(r.Options, opts) path := "v1/files" err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...) - return + return res, err } // AssetListResponseUnion contains all possible properties and values from [File], diff --git a/asset_test.go b/asset_test.go index d479ff3..f1fd203 100644 --- a/asset_test.go +++ b/asset_test.go @@ -14,7 +14,7 @@ import ( ) func TestAssetListWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL diff --git a/betav2file.go b/betav2file.go index 5417572..293eeed 100644 --- a/betav2file.go +++ b/betav2file.go @@ -53,10 +53,11 @@ func NewBetaV2FileService(opts ...option.RequestOption) (r BetaV2FileService) { // about how to implement secure client-side file upload. // // **File size limit** \ -// On the free plan, the maximum upload file sizes are 20MB for images, audio, and raw -// files, and 100MB for videos. On the paid plan, these limits increase to 40MB for -// images, audio, and raw files, and 2GB for videos. These limits can be further increased -// with higher-tier plans. +// On the free plan, the maximum upload file sizes are 25MB for images, audio, and raw +// files, and 100MB for videos. On the Lite paid plan, these limits increase to 40MB +// for images, audio, and raw files and 300MB for videos, whereas on the Pro paid plan, +// these limits increase to 50MB for images, audio, and raw files and 2GB for videos. +// These limits can be further increased with enterprise plans. // // **Version limit** \ // A file can have a maximum of 100 versions. @@ -74,13 +75,13 @@ func (r *BetaV2FileService) Upload(ctx context.Context, body BetaV2FileUploadPar opts = append([]option.RequestOption{option.WithBaseURL("https://upload.imagekit.io/")}, opts...) path := "api/v2/files/upload" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // Object containing details of a successful upload. type BetaV2FileUploadResponse struct { // An array of tags assigned to the uploaded file by auto tagging. - AITags []BetaV2FileUploadResponseAITag `json:"AITags,nullable"` + AITags []BetaV2FileUploadResponseAITag `json:"AITags" api:"nullable"` // The audio codec used in the video (only for video). AudioCodec string `json:"audioCodec"` // The bit rate of the video in kbps (only for video). @@ -89,7 +90,7 @@ type BetaV2FileUploadResponse struct { // `x,y,width,height`. If `customCoordinates` are not defined, then it is `null`. // Send `customCoordinates` in `responseFields` in API request to get the value of // this field. - CustomCoordinates string `json:"customCoordinates,nullable"` + CustomCoordinates string `json:"customCoordinates" api:"nullable"` // A key-value data associated with the asset. Use `responseField` in API request // to get `customMetadata` in the upload API response. Before setting any custom // metadata on an asset, you have to create the field using custom metadata fields @@ -151,7 +152,7 @@ type BetaV2FileUploadResponse struct { // The array of tags associated with the asset. If no tags are set, it will be // `null`. Send `tags` in `responseFields` in API request to get the value of this // field. - Tags []string `json:"tags,nullable"` + Tags []string `json:"tags" api:"nullable"` // In the case of an image, a small thumbnail URL. ThumbnailURL string `json:"thumbnailUrl"` // A publicly accessible URL of the file. @@ -268,7 +269,7 @@ type BetaV2FileUploadResponseSelectedFieldsSchema struct { // // Any of "Text", "Textarea", "Number", "Date", "Boolean", "SingleSelect", // "MultiSelect". - Type string `json:"type,required"` + Type string `json:"type" api:"required"` // The default value for this custom metadata field. The value should match the // `type` of custom metadata field. DefaultValue BetaV2FileUploadResponseSelectedFieldsSchemaDefaultValueUnion `json:"defaultValue"` @@ -569,7 +570,7 @@ type BetaV2FileUploadParams struct { // *bytes.Reader, *bytes.Buffer, *strings.Reader, or any stream). File io.Reader `json:"file,omitzero,required" format:"binary"` // The name with which the file has to be uploaded. - FileName string `json:"fileName,required"` + FileName string `json:"fileName" api:"required"` // This is the client-generated JSON Web Token (JWT). The ImageKit.io server uses // it to authenticate and check that the upload request parameters have not been // tampered with after the token has been generated. Learn how to create the token @@ -880,11 +881,11 @@ func init() { type BetaV2FileUploadParamsTransformationPostTransformation struct { // Transformation string (e.g. `w-200,h-200`). // Same syntax as ImageKit URL-based transformations. - Value string `json:"value,required"` + Value string `json:"value" api:"required"` // Transformation type. // // This field can be elided, and will marshal its zero value as "transformation". - Type constant.Transformation `json:"type,required"` + Type constant.Transformation `json:"type" default:"transformation"` paramObj } @@ -904,7 +905,7 @@ type BetaV2FileUploadParamsTransformationPostGifToVideo struct { // Converts an animated GIF into an MP4. // // This field can be elided, and will marshal its zero value as "gif-to-video". - Type constant.GifToVideo `json:"type,required"` + Type constant.GifToVideo `json:"type" default:"gif-to-video"` paramObj } @@ -924,7 +925,7 @@ type BetaV2FileUploadParamsTransformationPostThumbnail struct { // Generates a thumbnail image. // // This field can be elided, and will marshal its zero value as "thumbnail". - Type constant.Thumbnail `json:"type,required"` + Type constant.Thumbnail `json:"type" default:"thumbnail"` paramObj } @@ -941,13 +942,13 @@ type BetaV2FileUploadParamsTransformationPostAbs struct { // Streaming protocol to use (`hls` or `dash`). // // Any of "hls", "dash". - Protocol string `json:"protocol,omitzero,required"` + Protocol string `json:"protocol,omitzero" api:"required"` // List of different representations you want to create separated by an underscore. - Value string `json:"value,required"` + Value string `json:"value" api:"required"` // Adaptive Bitrate Streaming (ABS) setup. // // This field can be elided, and will marshal its zero value as "abs". - Type constant.Abs `json:"type,required"` + Type constant.Abs `json:"type" default:"abs"` paramObj } diff --git a/betav2file_test.go b/betav2file_test.go index 8f52587..45edf51 100644 --- a/betav2file_test.go +++ b/betav2file_test.go @@ -17,7 +17,7 @@ import ( ) func TestBetaV2FileUploadWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -31,7 +31,7 @@ func TestBetaV2FileUploadWithOptionalParams(t *testing.T) { option.WithPassword("My Password"), ) _, err := client.Beta.V2.Files.Upload(context.TODO(), imagekit.BetaV2FileUploadParams{ - File: io.Reader(bytes.NewBuffer([]byte("some file contents"))), + File: io.Reader(bytes.NewBuffer([]byte("Example data"))), FileName: "fileName", Token: imagekit.String("token"), Checks: imagekit.String("\"request.folder\" : \"marketing/\"\n"), diff --git a/cacheinvalidation.go b/cacheinvalidation.go index 8e24626..524c80c 100644 --- a/cacheinvalidation.go +++ b/cacheinvalidation.go @@ -42,7 +42,7 @@ func (r *CacheInvalidationService) New(ctx context.Context, body CacheInvalidati opts = slices.Concat(r.Options, opts) path := "v1/files/purge" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // This API returns the status of a purge cache request. @@ -50,11 +50,11 @@ func (r *CacheInvalidationService) Get(ctx context.Context, requestID string, op opts = slices.Concat(r.Options, opts) if requestID == "" { err = errors.New("missing required requestId parameter") - return + return nil, err } path := fmt.Sprintf("v1/files/purge/%s", requestID) err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + return res, err } type CacheInvalidationNewResponse struct { @@ -104,7 +104,7 @@ const ( type CacheInvalidationNewParams struct { // The full URL of the file to be purged. - URL string `json:"url,required" format:"uri"` + URL string `json:"url" api:"required" format:"uri"` paramObj } diff --git a/cacheinvalidation_test.go b/cacheinvalidation_test.go index 2e12514..ac4ecc1 100644 --- a/cacheinvalidation_test.go +++ b/cacheinvalidation_test.go @@ -14,7 +14,7 @@ import ( ) func TestCacheInvalidationNew(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -40,7 +40,7 @@ func TestCacheInvalidationNew(t *testing.T) { } func TestCacheInvalidationGet(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL diff --git a/client_test.go b/client_test.go index 1392578..9f7e535 100644 --- a/client_test.go +++ b/client_test.go @@ -41,7 +41,7 @@ func TestUserAgentHeader(t *testing.T) { }, }), ) - client.Files.Upload(context.Background(), imagekit.FileUploadParams{ + _, _ = client.Files.Upload(context.Background(), imagekit.FileUploadParams{ File: io.Reader(bytes.NewBuffer([]byte("https://www.example.com/public-url.jpg"))), FileName: "file-name.jpg", }) diff --git a/custommetadatafield.go b/custommetadatafield.go index eb701f8..964eba4 100644 --- a/custommetadatafield.go +++ b/custommetadatafield.go @@ -46,7 +46,7 @@ func (r *CustomMetadataFieldService) New(ctx context.Context, body CustomMetadat opts = slices.Concat(r.Options, opts) path := "v1/customMetadataFields" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // This API updates the label or schema of an existing custom metadata field. @@ -54,11 +54,11 @@ func (r *CustomMetadataFieldService) Update(ctx context.Context, id string, body opts = slices.Concat(r.Options, opts) if id == "" { err = errors.New("missing required id parameter") - return + return nil, err } path := fmt.Sprintf("v1/customMetadataFields/%s", id) err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, body, &res, opts...) - return + return res, err } // This API returns the array of created custom metadata field objects. By default @@ -73,7 +73,7 @@ func (r *CustomMetadataFieldService) List(ctx context.Context, query CustomMetad opts = slices.Concat(r.Options, opts) path := "v1/customMetadataFields" err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...) - return + return res, err } // This API deletes a custom metadata field. Even after deleting a custom metadata @@ -82,26 +82,26 @@ func (r *CustomMetadataFieldService) Delete(ctx context.Context, id string, opts opts = slices.Concat(r.Options, opts) if id == "" { err = errors.New("missing required id parameter") - return + return nil, err } path := fmt.Sprintf("v1/customMetadataFields/%s", id) err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &res, opts...) - return + return res, err } // Object containing details of a custom metadata field. type CustomMetadataField struct { // Unique identifier for the custom metadata field. Use this to update the field. - ID string `json:"id,required"` + ID string `json:"id" api:"required"` // Human readable name of the custom metadata field. This name is displayed as form // field label to the users while setting field value on the asset in the media // library UI. - Label string `json:"label,required"` + Label string `json:"label" api:"required"` // API name of the custom metadata field. This becomes the key while setting // `customMetadata` (key-value object) for an asset using upload or update API. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // An object that describes the rules for the custom metadata field value. - Schema CustomMetadataFieldSchema `json:"schema,required"` + Schema CustomMetadataFieldSchema `json:"schema" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { ID respjson.Field @@ -125,7 +125,7 @@ type CustomMetadataFieldSchema struct { // // Any of "Text", "Textarea", "Number", "Date", "Boolean", "SingleSelect", // "MultiSelect". - Type string `json:"type,required"` + Type string `json:"type" api:"required"` // The default value for this custom metadata field. Data type of default value // depends on the field type. DefaultValue CustomMetadataFieldSchemaDefaultValueUnion `json:"defaultValue"` @@ -399,11 +399,11 @@ type CustomMetadataFieldNewParams struct { // all non deleted custom metadata fields. This name is displayed as form field // label to the users while setting field value on an asset in the media library // UI. - Label string `json:"label,required"` + Label string `json:"label" api:"required"` // API name of the custom metadata field. This should be unique across all // (including deleted) custom metadata fields. - Name string `json:"name,required"` - Schema CustomMetadataFieldNewParamsSchema `json:"schema,omitzero,required"` + Name string `json:"name" api:"required"` + Schema CustomMetadataFieldNewParamsSchema `json:"schema,omitzero" api:"required"` paramObj } @@ -421,7 +421,7 @@ type CustomMetadataFieldNewParamsSchema struct { // // Any of "Text", "Textarea", "Number", "Date", "Boolean", "SingleSelect", // "MultiSelect". - Type string `json:"type,omitzero,required"` + Type string `json:"type,omitzero" api:"required"` // Sets this custom metadata field as required. Setting custom metadata fields on // an asset will throw error if the value for all required fields are not present // in upload or update asset API request body. diff --git a/custommetadatafield_test.go b/custommetadatafield_test.go index c3cb073..ca9bbbc 100644 --- a/custommetadatafield_test.go +++ b/custommetadatafield_test.go @@ -14,7 +14,7 @@ import ( ) func TestCustomMetadataFieldNewWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -69,7 +69,7 @@ func TestCustomMetadataFieldNewWithOptionalParams(t *testing.T) { } func TestCustomMetadataFieldUpdateWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -126,7 +126,7 @@ func TestCustomMetadataFieldUpdateWithOptionalParams(t *testing.T) { } func TestCustomMetadataFieldListWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -153,7 +153,7 @@ func TestCustomMetadataFieldListWithOptionalParams(t *testing.T) { } func TestCustomMetadataFieldDelete(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL diff --git a/dummy.go b/dummy.go index 5af366d..1391d11 100644 --- a/dummy.go +++ b/dummy.go @@ -41,7 +41,7 @@ func (r *DummyService) New(ctx context.Context, body DummyNewParams, opts ...opt opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) path := "v1/dummy/test" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, nil, opts...) - return + return err } type DummyNewParams struct { diff --git a/dummy_test.go b/dummy_test.go index 2ffd02b..95c415e 100644 --- a/dummy_test.go +++ b/dummy_test.go @@ -16,7 +16,7 @@ import ( ) func TestDummyNewWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -33,13 +33,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { BaseOverlay: shared.BaseOverlayParam{ LayerMode: shared.BaseOverlayLayerModeMultiply, Position: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, Timing: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ @@ -200,13 +207,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { BaseOverlayParam: shared.BaseOverlayParam{ LayerMode: shared.BaseOverlayLayerModeMultiply, Position: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, Timing: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ @@ -308,13 +322,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { BaseOverlayParam: shared.BaseOverlayParam{ LayerMode: shared.BaseOverlayLayerModeMultiply, Position: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, Timing: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ @@ -382,13 +403,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { BaseOverlayParam: shared.BaseOverlayParam{ LayerMode: shared.BaseOverlayLayerModeMultiply, Position: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, Timing: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ @@ -485,13 +513,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { BaseOverlayParam: shared.BaseOverlayParam{ LayerMode: shared.BaseOverlayLayerModeMultiply, Position: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, Timing: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ @@ -537,13 +572,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { }, }, OverlayPosition: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, OverlayTiming: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ @@ -583,13 +625,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { BaseOverlayParam: shared.BaseOverlayParam{ LayerMode: shared.BaseOverlayLayerModeMultiply, Position: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, Timing: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ @@ -697,13 +746,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { BaseOverlayParam: shared.BaseOverlayParam{ LayerMode: shared.BaseOverlayLayerModeMultiply, Position: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, Timing: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ @@ -801,13 +857,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { BaseOverlayParam: shared.BaseOverlayParam{ LayerMode: shared.BaseOverlayLayerModeMultiply, Position: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, Timing: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ @@ -846,13 +909,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { BaseOverlayParam: shared.BaseOverlayParam{ LayerMode: shared.BaseOverlayLayerModeMultiply, Position: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, Timing: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ @@ -975,13 +1045,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { BaseOverlayParam: shared.BaseOverlayParam{ LayerMode: shared.BaseOverlayLayerModeMultiply, Position: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, Timing: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ @@ -1077,13 +1154,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { BaseOverlayParam: shared.BaseOverlayParam{ LayerMode: shared.BaseOverlayLayerModeMultiply, Position: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, Timing: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ @@ -1151,13 +1235,20 @@ func TestDummyNewWithOptionalParams(t *testing.T) { BaseOverlayParam: shared.BaseOverlayParam{ LayerMode: shared.BaseOverlayLayerModeMultiply, Position: shared.OverlayPositionParam{ - Focus: shared.OverlayPositionFocusCenter, + AnchorPoint: shared.OverlayPositionAnchorPointTop, + Focus: shared.OverlayPositionFocusCenter, X: shared.OverlayPositionXUnionParam{ OfFloat: imagekit.Float(0), }, + XCenter: shared.OverlayPositionXCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, Y: shared.OverlayPositionYUnionParam{ OfFloat: imagekit.Float(0), }, + YCenter: shared.OverlayPositionYCenterUnionParam{ + OfFloat: imagekit.Float(0), + }, }, Timing: shared.OverlayTimingParam{ Duration: shared.OverlayTimingDurationUnionParam{ diff --git a/file.go b/file.go index bbd0f90..71d4826 100644 --- a/file.go +++ b/file.go @@ -58,11 +58,11 @@ func (r *FileService) Update(ctx context.Context, fileID string, body FileUpdate opts = slices.Concat(r.Options, opts) if fileID == "" { err = errors.New("missing required fileId parameter") - return + return nil, err } path := fmt.Sprintf("v1/files/%s/details", fileID) err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, body, &res, opts...) - return + return res, err } // This API deletes the file and all its file versions permanently. @@ -75,11 +75,11 @@ func (r *FileService) Delete(ctx context.Context, fileID string, opts ...option. opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if fileID == "" { err = errors.New("missing required fileId parameter") - return + return err } path := fmt.Sprintf("v1/files/%s", fileID) err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, nil, opts...) - return + return err } // This will copy a file from one folder to another. @@ -91,7 +91,7 @@ func (r *FileService) Copy(ctx context.Context, body FileCopyParams, opts ...opt opts = slices.Concat(r.Options, opts) path := "v1/files/copy" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // This API returns an object with details or attributes about the current version @@ -100,11 +100,11 @@ func (r *FileService) Get(ctx context.Context, fileID string, opts ...option.Req opts = slices.Concat(r.Options, opts) if fileID == "" { err = errors.New("missing required fileId parameter") - return + return nil, err } path := fmt.Sprintf("v1/files/%s/details", fileID) err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + return res, err } // This will move a file and all its versions from one folder to another. @@ -115,7 +115,7 @@ func (r *FileService) Move(ctx context.Context, body FileMoveParams, opts ...opt opts = slices.Concat(r.Options, opts) path := "v1/files/move" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // You can rename an already existing file in the media library using rename file @@ -127,7 +127,7 @@ func (r *FileService) Rename(ctx context.Context, body FileRenameParams, opts .. opts = slices.Concat(r.Options, opts) path := "v1/files/rename" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, body, &res, opts...) - return + return res, err } // ImageKit.io allows you to upload files directly from both the server and client @@ -141,10 +141,11 @@ func (r *FileService) Rename(ctx context.Context, body FileRenameParams, opts .. // by verifying the entire payload using JWT. // // **File size limit** \ -// On the free plan, the maximum upload file sizes are 20MB for images, audio, and raw -// files and 100MB for videos. On the paid plan, these limits increase to 40MB for images, -// audio, and raw files and 2GB for videos. These limits can be further increased with -// higher-tier plans. +// On the free plan, the maximum upload file sizes are 25MB for images, audio, and raw +// files and 100MB for videos. On the Lite paid plan, these limits increase to 40MB +// for images, audio, and raw files and 300MB for videos, whereas on the Pro paid plan, +// these limits increase to 50MB for images, audio, and raw files and 2GB for videos. +// These limits can be further increased with enterprise plans. // // **Version limit** \ // A file can have a maximum of 100 versions. @@ -162,13 +163,13 @@ func (r *FileService) Upload(ctx context.Context, body FileUploadParams, opts .. opts = append([]option.RequestOption{option.WithBaseURL("https://upload.imagekit.io/")}, opts...) path := "api/v1/files/upload" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // Object containing details of a file or file version. type File struct { // An array of tags assigned to the file by auto tagging. - AITags []FileAITag `json:"AITags,nullable"` + AITags []FileAITag `json:"AITags" api:"nullable"` // The audio codec used in the video (only for video/audio). AudioCodec string `json:"audioCodec"` // The bit rate of the video in kbps (only for video). @@ -177,7 +178,7 @@ type File struct { // format. CreatedAt time.Time `json:"createdAt" format:"date-time"` // An string with custom coordinates of the file. - CustomCoordinates string `json:"customCoordinates,nullable"` + CustomCoordinates string `json:"customCoordinates" api:"nullable"` // An object with custom metadata for the file. CustomMetadata map[string]any `json:"customMetadata"` // Optional text to describe the contents of the file. Can be set by the user or @@ -221,7 +222,7 @@ type File struct { Size float64 `json:"size"` // An array of tags assigned to the file. Tags are used to search files in the // media library. - Tags []string `json:"tags,nullable"` + Tags []string `json:"tags" api:"nullable"` // URL of the thumbnail image. This URL is used to access the thumbnail image of // the file in the media library. Thumbnail string `json:"thumbnail" format:"uri"` @@ -310,7 +311,7 @@ type FileSelectedFieldsSchema struct { // // Any of "Text", "Textarea", "Number", "Date", "Boolean", "SingleSelect", // "MultiSelect". - Type string `json:"type,required"` + Type string `json:"type" api:"required"` // The default value for this custom metadata field. The value should match the // `type` of custom metadata field. DefaultValue FileSelectedFieldsSchemaDefaultValueUnion `json:"defaultValue"` @@ -1018,7 +1019,7 @@ func (r *UpdateFileRequestChangePublicationStatusParam) UnmarshalJSON(data []byt // The property IsPublished is required. type UpdateFileRequestChangePublicationStatusPublishParam struct { // Set to `true` to publish the file. Set to `false` to unpublish the file. - IsPublished bool `json:"isPublished,required"` + IsPublished bool `json:"isPublished" api:"required"` // Set to `true` to publish/unpublish all versions of the file. Set to `false` to // publish/unpublish only the current version of the file. IncludeFileVersions param.Opt[bool] `json:"includeFileVersions,omitzero"` @@ -1129,7 +1130,7 @@ func (r *FileRenameResponse) UnmarshalJSON(data []byte) error { // Object containing details of a successful upload. type FileUploadResponse struct { // An array of tags assigned to the uploaded file by auto tagging. - AITags []FileUploadResponseAITag `json:"AITags,nullable"` + AITags []FileUploadResponseAITag `json:"AITags" api:"nullable"` // The audio codec used in the video (only for video). AudioCodec string `json:"audioCodec"` // The bit rate of the video in kbps (only for video). @@ -1138,7 +1139,7 @@ type FileUploadResponse struct { // `x,y,width,height`. If `customCoordinates` are not defined, then it is `null`. // Send `customCoordinates` in `responseFields` in API request to get the value of // this field. - CustomCoordinates string `json:"customCoordinates,nullable"` + CustomCoordinates string `json:"customCoordinates" api:"nullable"` // A key-value data associated with the asset. Use `responseField` in API request // to get `customMetadata` in the upload API response. Before setting any custom // metadata on an asset, you have to create the field using custom metadata fields @@ -1200,7 +1201,7 @@ type FileUploadResponse struct { // The array of tags associated with the asset. If no tags are set, it will be // `null`. Send `tags` in `responseFields` in API request to get the value of this // field. - Tags []string `json:"tags,nullable"` + Tags []string `json:"tags" api:"nullable"` // In the case of an image, a small thumbnail URL. ThumbnailURL string `json:"thumbnailUrl"` // A publicly accessible URL of the file. @@ -1317,7 +1318,7 @@ type FileUploadResponseSelectedFieldsSchema struct { // // Any of "Text", "Textarea", "Number", "Date", "Boolean", "SingleSelect", // "MultiSelect". - Type string `json:"type,required"` + Type string `json:"type" api:"required"` // The default value for this custom metadata field. The value should match the // `type` of custom metadata field. DefaultValue FileUploadResponseSelectedFieldsSchemaDefaultValueUnion `json:"defaultValue"` @@ -1615,14 +1616,14 @@ func (r FileUpdateParams) MarshalJSON() (data []byte, err error) { return shimjson.Marshal(r.UpdateFileRequest) } func (r *FileUpdateParams) UnmarshalJSON(data []byte) error { - return json.Unmarshal(data, &r.UpdateFileRequest) + return apijson.UnmarshalRoot(data, r) } type FileCopyParams struct { // Full path to the folder you want to copy the above file into. - DestinationPath string `json:"destinationPath,required"` + DestinationPath string `json:"destinationPath" api:"required"` // The full path of the file you want to copy. - SourceFilePath string `json:"sourceFilePath,required"` + SourceFilePath string `json:"sourceFilePath" api:"required"` // Option to copy all versions of a file. By default, only the current version of // the file is copied. When set to true, all versions of the file will be copied. // Default value - `false`. @@ -1640,9 +1641,9 @@ func (r *FileCopyParams) UnmarshalJSON(data []byte) error { type FileMoveParams struct { // Full path to the folder you want to move the above file into. - DestinationPath string `json:"destinationPath,required"` + DestinationPath string `json:"destinationPath" api:"required"` // The full path of the file you want to move. - SourceFilePath string `json:"sourceFilePath,required"` + SourceFilePath string `json:"sourceFilePath" api:"required"` paramObj } @@ -1656,14 +1657,14 @@ func (r *FileMoveParams) UnmarshalJSON(data []byte) error { type FileRenameParams struct { // The full path of the file you want to rename. - FilePath string `json:"filePath,required"` + FilePath string `json:"filePath" api:"required"` // The new name of the file. A filename can contain: // // Alphanumeric Characters: `a-z`, `A-Z`, `0-9` (including Unicode letters, marks, // and numerals in other languages). Special Characters: `.`, `_`, and `-`. // // Any other character, including space, will be replaced by `_`. - NewFileName string `json:"newFileName,required"` + NewFileName string `json:"newFileName" api:"required"` // Option to purge cache for the old file and its versions' URLs. // // When set to true, it will internally issue a purge cache request on CDN to @@ -1702,7 +1703,7 @@ type FileUploadParams struct { // - Special Characters: `.`, `-` // // Any other character including space will be replaced by `_` - FileName string `json:"fileName,required"` + FileName string `json:"fileName" api:"required"` // A unique value that the ImageKit.io server will use to recognize and prevent // subsequent retries for the same request. We suggest using V4 UUIDs, or another // random string with enough entropy to avoid collisions. This field is only @@ -2029,11 +2030,11 @@ func init() { type FileUploadParamsTransformationPostTransformation struct { // Transformation string (e.g. `w-200,h-200`). // Same syntax as ImageKit URL-based transformations. - Value string `json:"value,required"` + Value string `json:"value" api:"required"` // Transformation type. // // This field can be elided, and will marshal its zero value as "transformation". - Type constant.Transformation `json:"type,required"` + Type constant.Transformation `json:"type" default:"transformation"` paramObj } @@ -2053,7 +2054,7 @@ type FileUploadParamsTransformationPostGifToVideo struct { // Converts an animated GIF into an MP4. // // This field can be elided, and will marshal its zero value as "gif-to-video". - Type constant.GifToVideo `json:"type,required"` + Type constant.GifToVideo `json:"type" default:"gif-to-video"` paramObj } @@ -2073,7 +2074,7 @@ type FileUploadParamsTransformationPostThumbnail struct { // Generates a thumbnail image. // // This field can be elided, and will marshal its zero value as "thumbnail". - Type constant.Thumbnail `json:"type,required"` + Type constant.Thumbnail `json:"type" default:"thumbnail"` paramObj } @@ -2090,13 +2091,13 @@ type FileUploadParamsTransformationPostAbs struct { // Streaming protocol to use (`hls` or `dash`). // // Any of "hls", "dash". - Protocol string `json:"protocol,omitzero,required"` + Protocol string `json:"protocol,omitzero" api:"required"` // List of different representations you want to create separated by an underscore. - Value string `json:"value,required"` + Value string `json:"value" api:"required"` // Adaptive Bitrate Streaming (ABS) setup. // // This field can be elided, and will marshal its zero value as "abs". - Type constant.Abs `json:"type,required"` + Type constant.Abs `json:"type" default:"abs"` paramObj } diff --git a/file_test.go b/file_test.go index 6b57c74..6bd7ed9 100644 --- a/file_test.go +++ b/file_test.go @@ -17,7 +17,7 @@ import ( ) func TestFileUpdateWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -100,7 +100,7 @@ func TestFileUpdateWithOptionalParams(t *testing.T) { } func TestFileDelete(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -124,7 +124,7 @@ func TestFileDelete(t *testing.T) { } func TestFileCopyWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -152,7 +152,7 @@ func TestFileCopyWithOptionalParams(t *testing.T) { } func TestFileGet(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -176,7 +176,7 @@ func TestFileGet(t *testing.T) { } func TestFileMove(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -203,7 +203,7 @@ func TestFileMove(t *testing.T) { } func TestFileRenameWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -231,7 +231,7 @@ func TestFileRenameWithOptionalParams(t *testing.T) { } func TestFileUploadWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -245,7 +245,7 @@ func TestFileUploadWithOptionalParams(t *testing.T) { option.WithPassword("My Password"), ) _, err := client.Files.Upload(context.TODO(), imagekit.FileUploadParams{ - File: io.Reader(bytes.NewBuffer([]byte("some file contents"))), + File: io.Reader(bytes.NewBuffer([]byte("Example data"))), FileName: "fileName", Token: imagekit.String("token"), Checks: imagekit.String("\"request.folder\" : \"marketing/\"\n"), diff --git a/filebulk.go b/filebulk.go index 76b76f6..7b1a172 100644 --- a/filebulk.go +++ b/filebulk.go @@ -44,7 +44,7 @@ func (r *FileBulkService) Delete(ctx context.Context, body FileBulkDeleteParams, opts = slices.Concat(r.Options, opts) path := "v1/files/batch/deleteByFileIds" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // This API adds tags to multiple files in bulk. A maximum of 50 files can be @@ -53,7 +53,7 @@ func (r *FileBulkService) AddTags(ctx context.Context, body FileBulkAddTagsParam opts = slices.Concat(r.Options, opts) path := "v1/files/addTags" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // This API removes AITags from multiple files in bulk. A maximum of 50 files can @@ -62,7 +62,7 @@ func (r *FileBulkService) RemoveAITags(ctx context.Context, body FileBulkRemoveA opts = slices.Concat(r.Options, opts) path := "v1/files/removeAITags" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // This API removes tags from multiple files in bulk. A maximum of 50 files can be @@ -71,7 +71,7 @@ func (r *FileBulkService) RemoveTags(ctx context.Context, body FileBulkRemoveTag opts = slices.Concat(r.Options, opts) path := "v1/files/removeTags" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } type FileBulkDeleteResponse struct { @@ -144,7 +144,7 @@ func (r *FileBulkRemoveTagsResponse) UnmarshalJSON(data []byte) error { type FileBulkDeleteParams struct { // An array of fileIds which you want to delete. - FileIDs []string `json:"fileIds,omitzero,required"` + FileIDs []string `json:"fileIds,omitzero" api:"required"` paramObj } @@ -158,9 +158,9 @@ func (r *FileBulkDeleteParams) UnmarshalJSON(data []byte) error { type FileBulkAddTagsParams struct { // An array of fileIds to which you want to add tags. - FileIDs []string `json:"fileIds,omitzero,required"` + FileIDs []string `json:"fileIds,omitzero" api:"required"` // An array of tags that you want to add to the files. - Tags []string `json:"tags,omitzero,required"` + Tags []string `json:"tags,omitzero" api:"required"` paramObj } @@ -174,9 +174,9 @@ func (r *FileBulkAddTagsParams) UnmarshalJSON(data []byte) error { type FileBulkRemoveAITagsParams struct { // An array of AITags that you want to remove from the files. - AITags []string `json:"AITags,omitzero,required"` + AITags []string `json:"AITags,omitzero" api:"required"` // An array of fileIds from which you want to remove AITags. - FileIDs []string `json:"fileIds,omitzero,required"` + FileIDs []string `json:"fileIds,omitzero" api:"required"` paramObj } @@ -190,9 +190,9 @@ func (r *FileBulkRemoveAITagsParams) UnmarshalJSON(data []byte) error { type FileBulkRemoveTagsParams struct { // An array of fileIds from which you want to remove tags. - FileIDs []string `json:"fileIds,omitzero,required"` + FileIDs []string `json:"fileIds,omitzero" api:"required"` // An array of tags that you want to remove from the files. - Tags []string `json:"tags,omitzero,required"` + Tags []string `json:"tags,omitzero" api:"required"` paramObj } diff --git a/filebulk_test.go b/filebulk_test.go index 1cb0db1..5da35a6 100644 --- a/filebulk_test.go +++ b/filebulk_test.go @@ -14,7 +14,7 @@ import ( ) func TestFileBulkDelete(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -40,7 +40,7 @@ func TestFileBulkDelete(t *testing.T) { } func TestFileBulkAddTags(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -67,7 +67,7 @@ func TestFileBulkAddTags(t *testing.T) { } func TestFileBulkRemoveAITags(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -94,7 +94,7 @@ func TestFileBulkRemoveAITags(t *testing.T) { } func TestFileBulkRemoveTags(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL diff --git a/filemetadata.go b/filemetadata.go index 07f7b05..6d221c1 100644 --- a/filemetadata.go +++ b/filemetadata.go @@ -43,11 +43,11 @@ func (r *FileMetadataService) Get(ctx context.Context, fileID string, opts ...op opts = slices.Concat(r.Options, opts) if fileID == "" { err = errors.New("missing required fileId parameter") - return + return nil, err } path := fmt.Sprintf("v1/files/%s/metadata", fileID) err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + return res, err } // Get image EXIF, pHash, and other metadata from ImageKit.io powered remote URL @@ -56,13 +56,13 @@ func (r *FileMetadataService) GetFromURL(ctx context.Context, query FileMetadata opts = slices.Concat(r.Options, opts) path := "v1/metadata" err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, query, &res, opts...) - return + return res, err } type FileMetadataGetFromURLParams struct { // Should be a valid file URL. It should be accessible using your ImageKit.io // account. - URL string `query:"url,required" format:"uri" json:"-"` + URL string `query:"url" api:"required" format:"uri" json:"-"` paramObj } diff --git a/filemetadata_test.go b/filemetadata_test.go index 0245da8..d5f2771 100644 --- a/filemetadata_test.go +++ b/filemetadata_test.go @@ -14,7 +14,7 @@ import ( ) func TestFileMetadataGet(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -38,7 +38,7 @@ func TestFileMetadataGet(t *testing.T) { } func TestFileMetadataGetFromURL(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL diff --git a/fileversion.go b/fileversion.go index 6a07b1d..57a490b 100644 --- a/fileversion.go +++ b/fileversion.go @@ -39,11 +39,11 @@ func (r *FileVersionService) List(ctx context.Context, fileID string, opts ...op opts = slices.Concat(r.Options, opts) if fileID == "" { err = errors.New("missing required fileId parameter") - return + return nil, err } path := fmt.Sprintf("v1/files/%s/versions", fileID) err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + return res, err } // This API deletes a non-current file version permanently. The API returns an @@ -54,15 +54,15 @@ func (r *FileVersionService) Delete(ctx context.Context, versionID string, body opts = slices.Concat(r.Options, opts) if body.FileID == "" { err = errors.New("missing required fileId parameter") - return + return nil, err } if versionID == "" { err = errors.New("missing required versionId parameter") - return + return nil, err } path := fmt.Sprintf("v1/files/%s/versions/%s", body.FileID, versionID) err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, &res, opts...) - return + return res, err } // This API returns an object with details or attributes of a file version. @@ -70,15 +70,15 @@ func (r *FileVersionService) Get(ctx context.Context, versionID string, query Fi opts = slices.Concat(r.Options, opts) if query.FileID == "" { err = errors.New("missing required fileId parameter") - return + return nil, err } if versionID == "" { err = errors.New("missing required versionId parameter") - return + return nil, err } path := fmt.Sprintf("v1/files/%s/versions/%s", query.FileID, versionID) err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + return res, err } // This API restores a file version as the current file version. @@ -86,15 +86,15 @@ func (r *FileVersionService) Restore(ctx context.Context, versionID string, body opts = slices.Concat(r.Options, opts) if body.FileID == "" { err = errors.New("missing required fileId parameter") - return + return nil, err } if versionID == "" { err = errors.New("missing required versionId parameter") - return + return nil, err } path := fmt.Sprintf("v1/files/%s/versions/%s/restore", body.FileID, versionID) err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, nil, &res, opts...) - return + return res, err } type FileVersionDeleteResponse struct { @@ -112,16 +112,16 @@ func (r *FileVersionDeleteResponse) UnmarshalJSON(data []byte) error { } type FileVersionDeleteParams struct { - FileID string `path:"fileId,required" json:"-"` + FileID string `path:"fileId" api:"required" json:"-"` paramObj } type FileVersionGetParams struct { - FileID string `path:"fileId,required" json:"-"` + FileID string `path:"fileId" api:"required" json:"-"` paramObj } type FileVersionRestoreParams struct { - FileID string `path:"fileId,required" json:"-"` + FileID string `path:"fileId" api:"required" json:"-"` paramObj } diff --git a/fileversion_test.go b/fileversion_test.go index e6d5499..80d6d42 100644 --- a/fileversion_test.go +++ b/fileversion_test.go @@ -14,7 +14,7 @@ import ( ) func TestFileVersionList(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -38,7 +38,7 @@ func TestFileVersionList(t *testing.T) { } func TestFileVersionDelete(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -68,7 +68,7 @@ func TestFileVersionDelete(t *testing.T) { } func TestFileVersionGet(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -98,7 +98,7 @@ func TestFileVersionGet(t *testing.T) { } func TestFileVersionRestore(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL diff --git a/folder.go b/folder.go index e21c026..3fecf68 100644 --- a/folder.go +++ b/folder.go @@ -41,7 +41,7 @@ func (r *FolderService) New(ctx context.Context, body FolderNewParams, opts ...o opts = slices.Concat(r.Options, opts) path := "v1/folder" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // This will delete a folder and all its contents permanently. The API returns an @@ -50,7 +50,7 @@ func (r *FolderService) Delete(ctx context.Context, body FolderDeleteParams, opt opts = slices.Concat(r.Options, opts) path := "v1/folder" err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, body, &res, opts...) - return + return res, err } // This will copy one folder into another. The selected folder, its nested folders, @@ -62,7 +62,7 @@ func (r *FolderService) Copy(ctx context.Context, body FolderCopyParams, opts .. opts = slices.Concat(r.Options, opts) path := "v1/bulkJobs/copyFolder" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // This will move one folder into another. The selected folder, its nested folders, @@ -73,7 +73,7 @@ func (r *FolderService) Move(ctx context.Context, body FolderMoveParams, opts .. opts = slices.Concat(r.Options, opts) path := "v1/bulkJobs/moveFolder" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // This API allows you to rename an existing folder. The folder and all its nested @@ -83,7 +83,7 @@ func (r *FolderService) Rename(ctx context.Context, body FolderRenameParams, opt opts = slices.Concat(r.Options, opts) path := "v1/bulkJobs/renameFolder" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } type FolderNewResponse struct { @@ -118,7 +118,7 @@ func (r *FolderDeleteResponse) UnmarshalJSON(data []byte) error { type FolderCopyResponse struct { // Unique identifier of the bulk job. This can be used to check the status of the // bulk job. - JobID string `json:"jobId,required"` + JobID string `json:"jobId" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { JobID respjson.Field @@ -137,7 +137,7 @@ func (r *FolderCopyResponse) UnmarshalJSON(data []byte) error { type FolderMoveResponse struct { // Unique identifier of the bulk job. This can be used to check the status of the // bulk job. - JobID string `json:"jobId,required"` + JobID string `json:"jobId" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { JobID respjson.Field @@ -156,7 +156,7 @@ func (r *FolderMoveResponse) UnmarshalJSON(data []byte) error { type FolderRenameResponse struct { // Unique identifier of the bulk job. This can be used to check the status of the // bulk job. - JobID string `json:"jobId,required"` + JobID string `json:"jobId" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { JobID respjson.Field @@ -177,7 +177,7 @@ type FolderNewParams struct { // All characters except alphabets and numbers (inclusive of unicode letters, // marks, and numerals in other languages) will be replaced by an underscore i.e. // `_`. - FolderName string `json:"folderName,required"` + FolderName string `json:"folderName" api:"required"` // The folder where the new folder should be created, for root use `/` else the // path e.g. `containing/folder/`. // @@ -185,7 +185,7 @@ type FolderNewParams struct { // be automatically created. For example, if you pass `/product/images/summer`, // then `product`, `images`, and `summer` folders will be created if they don't // already exist. - ParentFolderPath string `json:"parentFolderPath,required"` + ParentFolderPath string `json:"parentFolderPath" api:"required"` paramObj } @@ -199,7 +199,7 @@ func (r *FolderNewParams) UnmarshalJSON(data []byte) error { type FolderDeleteParams struct { // Full path to the folder you want to delete. For example `/folder/to/delete/`. - FolderPath string `json:"folderPath,required"` + FolderPath string `json:"folderPath" api:"required"` paramObj } @@ -214,9 +214,9 @@ func (r *FolderDeleteParams) UnmarshalJSON(data []byte) error { type FolderCopyParams struct { // Full path to the destination folder where you want to copy the source folder // into. - DestinationPath string `json:"destinationPath,required"` + DestinationPath string `json:"destinationPath" api:"required"` // The full path to the source folder you want to copy. - SourceFolderPath string `json:"sourceFolderPath,required"` + SourceFolderPath string `json:"sourceFolderPath" api:"required"` // Option to copy all versions of files that are nested inside the selected folder. // By default, only the current version of each file will be copied. When set to // true, all versions of each file will be copied. Default value - `false`. @@ -235,9 +235,9 @@ func (r *FolderCopyParams) UnmarshalJSON(data []byte) error { type FolderMoveParams struct { // Full path to the destination folder where you want to move the source folder // into. - DestinationPath string `json:"destinationPath,required"` + DestinationPath string `json:"destinationPath" api:"required"` // The full path to the source folder you want to move. - SourceFolderPath string `json:"sourceFolderPath,required"` + SourceFolderPath string `json:"sourceFolderPath" api:"required"` paramObj } @@ -251,13 +251,13 @@ func (r *FolderMoveParams) UnmarshalJSON(data []byte) error { type FolderRenameParams struct { // The full path to the folder you want to rename. - FolderPath string `json:"folderPath,required"` + FolderPath string `json:"folderPath" api:"required"` // The new name for the folder. // // All characters except alphabets and numbers (inclusive of unicode letters, // marks, and numerals in other languages) and `-` will be replaced by an // underscore i.e. `_`. - NewFolderName string `json:"newFolderName,required"` + NewFolderName string `json:"newFolderName" api:"required"` // Option to purge cache for the old nested files and their versions' URLs. // // When set to true, it will internally issue a purge cache request on CDN to diff --git a/folder_test.go b/folder_test.go index b891101..ec03029 100644 --- a/folder_test.go +++ b/folder_test.go @@ -14,7 +14,7 @@ import ( ) func TestFolderNew(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -41,7 +41,7 @@ func TestFolderNew(t *testing.T) { } func TestFolderDelete(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -67,7 +67,7 @@ func TestFolderDelete(t *testing.T) { } func TestFolderCopyWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -95,7 +95,7 @@ func TestFolderCopyWithOptionalParams(t *testing.T) { } func TestFolderMove(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -122,7 +122,7 @@ func TestFolderMove(t *testing.T) { } func TestFolderRenameWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL diff --git a/folderjob.go b/folderjob.go index 8253935..b0eb5df 100644 --- a/folderjob.go +++ b/folderjob.go @@ -39,11 +39,11 @@ func (r *FolderJobService) Get(ctx context.Context, jobID string, opts ...option opts = slices.Concat(r.Options, opts) if jobID == "" { err = errors.New("missing required jobId parameter") - return + return nil, err } path := fmt.Sprintf("v1/bulkJobs/%s", jobID) err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + return res, err } type FolderJobGetResponse struct { diff --git a/folderjob_test.go b/folderjob_test.go index a4c9541..f03c188 100644 --- a/folderjob_test.go +++ b/folderjob_test.go @@ -14,7 +14,7 @@ import ( ) func TestFolderJobGet(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL diff --git a/go.mod b/go.mod index f306eb5..12b1fb0 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-20260114220421-3f69fd681bb0 + github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20260309172517-425968d811b9 github.com/tidwall/gjson v1.18.0 github.com/tidwall/sjson v1.2.5 ) diff --git a/go.sum b/go.sum index b09e3fe..ff28d75 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20260114220421-3f69fd681bb0 h1:EZXYkItlI9VXF+3x/VFkP8JKa6ibJVZAMjHGfdjzHC8= -github.com/standard-webhooks/standard-webhooks/libraries v0.0.0-20260114220421-3f69fd681bb0/go.mod h1:L1MQhA6x4dn9r007T033lsaZMv9EmBAdXyU/+EF40fo= +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/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/apiform/encoder.go b/internal/apiform/encoder.go index 58f5621..ab31015 100644 --- a/internal/apiform/encoder.go +++ b/internal/apiform/encoder.go @@ -183,6 +183,18 @@ func (e *encoder) newPrimitiveTypeEncoder(t reflect.Type) encoderFunc { func (e *encoder) newArrayTypeEncoder(t reflect.Type) encoderFunc { itemEncoder := e.typeEncoder(t.Elem()) keyFn := e.arrayKeyEncoder() + if e.arrayFmt == "comma" { + return func(key string, v reflect.Value, writer *multipart.Writer) error { + if v.Len() == 0 { + return nil + } + elements := make([]string, v.Len()) + for i := 0; i < v.Len(); i++ { + elements[i] = fmt.Sprint(v.Index(i).Interface()) + } + return writer.WriteField(key, strings.Join(elements, ",")) + } + } return func(key string, v reflect.Value, writer *multipart.Writer) error { if keyFn == nil { return fmt.Errorf("apiform: unsupported array format") @@ -265,6 +277,14 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc { } return typeEncoderFn(key, value, writer) } + } else if ptag.defaultValue != nil { + typeEncoderFn := e.typeEncoder(field.Type) + encoderFn = func(key string, value reflect.Value, writer *multipart.Writer) error { + if value.IsZero() { + return typeEncoderFn(key, reflect.ValueOf(ptag.defaultValue), writer) + } + return typeEncoderFn(key, value, writer) + } } else { encoderFn = e.typeEncoder(field.Type) } @@ -469,5 +489,5 @@ func WriteExtras(writer *multipart.Writer, extras map[string]any) (err error) { break } } - return + return err } diff --git a/internal/apiform/form_test.go b/internal/apiform/form_test.go index 86cb43d..1751e27 100644 --- a/internal/apiform/form_test.go +++ b/internal/apiform/form_test.go @@ -48,18 +48,18 @@ type DateTime struct { type AdditionalProperties struct { A bool `form:"a"` - Extras map[string]any `form:"-,extras"` + Extras map[string]any `form:"-" api:"extrafields"` } type TypedAdditionalProperties struct { A bool `form:"a"` - Extras map[string]int `form:"-,extras"` + Extras map[string]int `form:"-" api:"extrafields"` } type EmbeddedStructs struct { AdditionalProperties A *int `form:"number2"` - Extras map[string]any `form:"-,extras"` + Extras map[string]any `form:"-" api:"extrafields"` } type Recursive struct { @@ -123,6 +123,11 @@ type StructUnion struct { param.APIUnion } +type ConstantStruct struct { + Anchor string `form:"anchor" default:"created_at"` + Seconds int `form:"seconds"` +} + type MultipartMarshalerParent struct { Middle MultipartMarshalerMiddleNext `form:"middle"` } @@ -554,6 +559,37 @@ Content-Disposition: form-data; name="union" Union: UnionTime(time.Date(2010, 05, 23, 0, 0, 0, 0, time.UTC)), }, }, + "constant_zero_value": { + `--xxx +Content-Disposition: form-data; name="anchor" + +created_at +--xxx +Content-Disposition: form-data; name="seconds" + +3600 +--xxx-- +`, + ConstantStruct{ + Seconds: 3600, + }, + }, + "constant_explicit_value": { + `--xxx +Content-Disposition: form-data; name="anchor" + +created_at_override +--xxx +Content-Disposition: form-data; name="seconds" + +3600 +--xxx-- +`, + ConstantStruct{ + Anchor: "created_at_override", + Seconds: 3600, + }, + }, "deeply-nested-struct,brackets": { `--xxx Content-Disposition: form-data; name="middle[middleNext][child]" @@ -585,14 +621,17 @@ func TestEncode(t *testing.T) { t.Run(name, func(t *testing.T) { buf := bytes.NewBuffer(nil) writer := multipart.NewWriter(buf) - writer.SetBoundary("xxx") + err := writer.SetBoundary("xxx") + if err != nil { + t.Errorf("setting boundary for %v failed with error %v", test.val, err) + } - var arrayFmt string = "indices:dots" + arrayFmt := "indices:dots" if tags := strings.Split(name, ","); len(tags) > 1 { arrayFmt = tags[1] } - err := MarshalWithSettings(test.val, writer, arrayFmt) + err = MarshalWithSettings(test.val, writer, arrayFmt) if err != nil { t.Errorf("serialization of %v failed with error %v", test.val, err) } diff --git a/internal/apiform/tag.go b/internal/apiform/tag.go index 736fc1e..f0c9d14 100644 --- a/internal/apiform/tag.go +++ b/internal/apiform/tag.go @@ -5,16 +5,19 @@ import ( "strings" ) +const apiStructTag = "api" const jsonStructTag = "json" const formStructTag = "form" const formatStructTag = "format" +const defaultStructTag = "default" type parsedStructTag struct { - name string - required bool - extras bool - metadata bool - omitzero bool + name string + required bool + extras bool + metadata bool + omitzero bool + defaultValue any } func parseFormStructTag(field reflect.StructField) (tag parsedStructTag, ok bool) { @@ -23,7 +26,7 @@ func parseFormStructTag(field reflect.StructField) (tag parsedStructTag, ok bool raw, ok = field.Tag.Lookup(jsonStructTag) } if !ok { - return + return tag, ok } parts := strings.Split(raw, ",") if len(parts) == 0 { @@ -42,10 +45,44 @@ func parseFormStructTag(field reflect.StructField) (tag parsedStructTag, ok bool tag.omitzero = true } } - return + + parseApiStructTag(field, &tag) + parseDefaultStructTag(field, &tag) + return tag, ok +} + +func parseDefaultStructTag(field reflect.StructField, tag *parsedStructTag) { + if field.Type.Kind() != reflect.String { + // Only strings are currently supported + return + } + + raw, ok := field.Tag.Lookup(defaultStructTag) + if !ok { + return + } + tag.defaultValue = raw +} + +func parseApiStructTag(field reflect.StructField, tag *parsedStructTag) { + raw, ok := field.Tag.Lookup(apiStructTag) + if !ok { + return + } + parts := strings.Split(raw, ",") + for _, part := range parts { + switch part { + case "extrafields": + tag.extras = true + case "required": + tag.required = true + case "metadata": + tag.metadata = true + } + } } func parseFormatStructTag(field reflect.StructField) (format string, ok bool) { format, ok = field.Tag.Lookup(formatStructTag) - return + return format, ok } diff --git a/internal/apijson/decodeparam_test.go b/internal/apijson/decodeparam_test.go index be371d0..198136d 100644 --- a/internal/apijson/decodeparam_test.go +++ b/internal/apijson/decodeparam_test.go @@ -50,10 +50,10 @@ func TestOptionalDecoders(t *testing.T) { type paramObject = param.APIObject type BasicObject struct { - ReqInt int64 `json:"req_int,required"` - ReqFloat float64 `json:"req_float,required"` - ReqString string `json:"req_string,required"` - ReqBool bool `json:"req_bool,required"` + ReqInt int64 `json:"req_int" api:"required"` + ReqFloat float64 `json:"req_float" api:"required"` + ReqString string `json:"req_string" api:"required"` + ReqBool bool `json:"req_bool" api:"required"` OptInt param.Opt[int64] `json:"opt_int"` OptFloat param.Opt[float64] `json:"opt_float"` @@ -110,7 +110,7 @@ func TestBasicObject(t *testing.T) { } type ComplexObject struct { - Basic BasicObject `json:"basic,required"` + Basic BasicObject `json:"basic" api:"required"` Enum string `json:"enum"` paramObject } @@ -152,29 +152,29 @@ func TestComplexObject(t *testing.T) { type paramUnion = param.APIUnion type MemberA struct { - Name string `json:"name,required"` - Age int `json:"age,required"` + Name string `json:"name" api:"required"` + Age int `json:"age" api:"required"` } type MemberB struct { - Name string `json:"name,required"` - Age string `json:"age,required"` + Name string `json:"name" api:"required"` + Age string `json:"age" api:"required"` } type MemberC struct { - Name string `json:"name,required"` - Age int `json:"age,required"` + Name string `json:"name" api:"required"` + Age int `json:"age" api:"required"` Status string `json:"status"` } type MemberD struct { - Cost int `json:"cost,required"` - Status string `json:"status,required"` + Cost int `json:"cost" api:"required"` + Status string `json:"status" api:"required"` } type MemberE struct { - Cost int `json:"cost,required"` - Status string `json:"status,required"` + Cost int `json:"cost" api:"required"` + Status string `json:"status" api:"required"` } type MemberF struct { @@ -318,21 +318,21 @@ func (c ConstantB) Default() string { return "B" } func (c ConstantC) Default() string { return "C" } type DiscVariantA struct { - Name string `json:"name,required"` - Age int `json:"age,required"` - Type ConstantA `json:"type,required"` + Name string `json:"name" api:"required"` + Age int `json:"age" api:"required"` + Type ConstantA `json:"type" api:"required"` } type DiscVariantB struct { - Name string `json:"name,required"` - Age int `json:"age,required"` - Type ConstantB `json:"type,required"` + Name string `json:"name" api:"required"` + Age int `json:"age" api:"required"` + Type ConstantB `json:"type" api:"required"` } type DiscVariantC struct { - Name string `json:"name,required"` - Age float64 `json:"age,required"` - Type ConstantC `json:"type,required"` + Name string `json:"name" api:"required"` + Age float64 `json:"age" api:"required"` + Type ConstantC `json:"type" api:"required"` } type DiscriminatedUnion struct { @@ -352,13 +352,13 @@ func init() { } type FooVariant struct { - Type string `json:"type,required"` - Value string `json:"value,required"` + Type string `json:"type" api:"required"` + Value string `json:"value" api:"required"` } type BarVariant struct { - Type string `json:"type,required"` - Enable bool `json:"enable,required"` + Type string `json:"type" api:"required"` + Enable bool `json:"enable" api:"required"` } type MultiDiscriminatorUnion struct { diff --git a/internal/apijson/decoder.go b/internal/apijson/decoder.go index b9729db..44ffc9a 100644 --- a/internal/apijson/decoder.go +++ b/internal/apijson/decoder.go @@ -393,7 +393,7 @@ func (d *decoderBuilder) newStructTypeDecoder(t reflect.Type) decoderFunc { for _, decoder := range anonymousDecoders { // ignore errors - decoder.fn(node, value.FieldByIndex(decoder.idx), state) + _ = decoder.fn(node, value.FieldByIndex(decoder.idx), state) } for _, inlineDecoder := range inlineDecoders { @@ -462,7 +462,7 @@ func (d *decoderBuilder) newStructTypeDecoder(t reflect.Type) decoderFunc { // Handle null [param.Opt] if itemNode.Type == gjson.Null && dest.IsValid() && dest.Type().Implements(reflect.TypeOf((*param.Optional)(nil)).Elem()) { - dest.Addr().Interface().(json.Unmarshaler).UnmarshalJSON([]byte(itemNode.Raw)) + _ = dest.Addr().Interface().(json.Unmarshaler).UnmarshalJSON([]byte(itemNode.Raw)) continue } @@ -684,8 +684,5 @@ func guardUnknown(state *decoderState, v reflect.Value) bool { constantString, ok := v.Interface().(interface{ Default() string }) named := v.Type() != stringType - if guardStrict(state, ok && named && v.Equal(reflect.ValueOf(constantString.Default()))) { - return true - } - return false + return guardStrict(state, ok && named && v.Equal(reflect.ValueOf(constantString.Default()))) } diff --git a/internal/apijson/decoderesp_test.go b/internal/apijson/decoderesp_test.go index ca22fba..f467265 100644 --- a/internal/apijson/decoderesp_test.go +++ b/internal/apijson/decoderesp_test.go @@ -8,7 +8,7 @@ import ( ) type StructWithNullExtraField struct { - Results []string `json:"results,required"` + Results []string `json:"results" api:"required"` JSON struct { Results respjson.Field ExtraFields map[string]respjson.Field diff --git a/internal/apijson/encoder.go b/internal/apijson/encoder.go index ab7a3c1..7c71153 100644 --- a/internal/apijson/encoder.go +++ b/internal/apijson/encoder.go @@ -12,6 +12,8 @@ import ( "time" "github.com/tidwall/sjson" + + shimjson "github.com/imagekit-developer/imagekit-go/v2/internal/encoding/json" ) var encoders sync.Map // map[encoderEntry]encoderFunc @@ -271,6 +273,12 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc { if err != nil { return nil, err } + if ef.tag.defaultValue != nil && (!field.IsValid() || field.IsZero()) { + encoded, err = shimjson.Marshal(ef.tag.defaultValue) + if err != nil { + return nil, err + } + } if encoded == nil { continue } @@ -286,28 +294,7 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc { return nil, err } } - return - } -} - -func (e *encoder) newFieldTypeEncoder(t reflect.Type) encoderFunc { - f, _ := t.FieldByName("Value") - enc := e.typeEncoder(f.Type) - - return func(value reflect.Value) (json []byte, err error) { - present := value.FieldByName("Present") - if !present.Bool() { - return nil, nil - } - null := value.FieldByName("Null") - if null.Bool() { - return []byte("null"), nil - } - raw := value.FieldByName("Raw") - if !raw.IsNil() { - return e.typeEncoder(raw.Type())(raw) - } - return enc(value.FieldByName("Value")) + return json, err } } diff --git a/internal/apijson/enum.go b/internal/apijson/enum.go index 5bef11c..a1626a5 100644 --- a/internal/apijson/enum.go +++ b/internal/apijson/enum.go @@ -4,7 +4,6 @@ import ( "fmt" "reflect" "slices" - "sync" "github.com/tidwall/gjson" ) @@ -15,7 +14,6 @@ import ( type validationEntry struct { field reflect.StructField - required bool legalValues struct { strings []string // 1 represents true, 0 represents false, -1 represents either @@ -24,9 +22,6 @@ type validationEntry struct { } } -type validatorFunc func(reflect.Value) exactness - -var validators sync.Map var validationRegistry = map[reflect.Type][]validationEntry{} func RegisterFieldValidator[T any, V string | bool | int | float64](fieldName string, values ...V) { @@ -111,9 +106,9 @@ func (state *decoderState) validateBool(v reflect.Value) { return } b := v.Bool() - if state.validator.legalValues.bools == 1 && b == false { + if state.validator.legalValues.bools == 1 && !b { state.exactness = loose - } else if state.validator.legalValues.bools == 0 && b == true { + } else if state.validator.legalValues.bools == 0 && b { state.exactness = loose } } diff --git a/internal/apijson/json_test.go b/internal/apijson/json_test.go index 02904d2..2853bf9 100644 --- a/internal/apijson/json_test.go +++ b/internal/apijson/json_test.go @@ -40,12 +40,12 @@ type DateTime struct { type AdditionalProperties struct { A bool `json:"a"` - ExtraFields map[string]any `json:"-,extras"` + ExtraFields map[string]any `json:"-" api:"extrafields"` } type TypedAdditionalProperties struct { A bool `json:"a"` - ExtraFields map[string]int `json:"-,extras"` + ExtraFields map[string]int `json:"-" api:"extrafields"` } type EmbeddedStruct struct { @@ -65,7 +65,7 @@ type EmbeddedStructJSON struct { type EmbeddedStructs struct { EmbeddedStruct A *int `json:"a"` - ExtraFields map[string]any `json:"-,extras"` + ExtraFields map[string]any `json:"-" api:"extrafields"` JSON EmbeddedStructsJSON } @@ -86,8 +86,8 @@ type JSONFieldStruct struct { B int64 `json:"b"` C string `json:"c"` D string `json:"d"` - ExtraFields map[string]int64 `json:",extras"` - JSON JSONFieldStructJSON `json:",metadata"` + ExtraFields map[string]int64 `json:"" api:"extrafields"` + JSON JSONFieldStructJSON `json:"-" api:"metadata"` } type JSONFieldStructJSON struct { @@ -113,12 +113,12 @@ type Union interface { type Inline struct { InlineField Primitives `json:",inline"` - JSON InlineJSON `json:",metadata"` + JSON InlineJSON `json:"-" api:"metadata"` } type InlineArray struct { InlineField []string `json:",inline"` - JSON InlineJSON `json:",metadata"` + JSON InlineJSON `json:"-" api:"metadata"` } type InlineJSON struct { @@ -268,7 +268,7 @@ type MarshallingUnionStruct struct { func (r *MarshallingUnionStruct) UnmarshalJSON(data []byte) (err error) { *r = MarshallingUnionStruct{} err = UnmarshalRoot(data, &r.Union) - return + return err } func (r MarshallingUnionStruct) MarshalJSON() (data []byte, err error) { @@ -614,3 +614,20 @@ func TestEncode(t *testing.T) { }) } } + +type StructWithDefault struct { + Type string `json:"type" default:"foo"` +} + +func TestDefault(t *testing.T) { + value := StructWithDefault{} + expected := `{"type":"foo"}` + + raw, err := Marshal(value) + if err != nil { + t.Fatalf("serialization of %v failed with error %v", value, err) + } + if string(raw) != expected { + t.Fatalf("expected %+#v to serialize to %s but got %s", value, expected, string(raw)) + } +} diff --git a/internal/apijson/tag.go b/internal/apijson/tag.go index 812fb3c..efcaf8c 100644 --- a/internal/apijson/tag.go +++ b/internal/apijson/tag.go @@ -5,21 +5,24 @@ import ( "strings" ) +const apiStructTag = "api" const jsonStructTag = "json" const formatStructTag = "format" +const defaultStructTag = "default" type parsedStructTag struct { - name string - required bool - extras bool - metadata bool - inline bool + name string + required bool + extras bool + metadata bool + inline bool + defaultValue any } func parseJSONStructTag(field reflect.StructField) (tag parsedStructTag, ok bool) { raw, ok := field.Tag.Lookup(jsonStructTag) if !ok { - return + return tag, ok } parts := strings.Split(raw, ",") if len(parts) == 0 { @@ -38,10 +41,45 @@ func parseJSONStructTag(field reflect.StructField) (tag parsedStructTag, ok bool tag.inline = true } } - return + + // the `api` struct tag is only used alongside `json` for custom behaviour + parseApiStructTag(field, &tag) + parseDefaultStructTag(field, &tag) + return tag, ok +} + +func parseDefaultStructTag(field reflect.StructField, tag *parsedStructTag) { + if field.Type.Kind() != reflect.String { + // Only strings are currently supported + return + } + + raw, ok := field.Tag.Lookup(defaultStructTag) + if !ok { + return + } + tag.defaultValue = raw +} + +func parseApiStructTag(field reflect.StructField, tag *parsedStructTag) { + raw, ok := field.Tag.Lookup(apiStructTag) + if !ok { + return + } + parts := strings.Split(raw, ",") + for _, part := range parts { + switch part { + case "extrafields": + tag.extras = true + case "required": + tag.required = true + case "metadata": + tag.metadata = true + } + } } func parseFormatStructTag(field reflect.StructField) (format string, ok bool) { format, ok = field.Tag.Lookup(formatStructTag) - return + return format, ok } diff --git a/internal/apiquery/encoder.go b/internal/apiquery/encoder.go index 93d9637..7e4f49d 100644 --- a/internal/apiquery/encoder.go +++ b/internal/apiquery/encoder.go @@ -103,7 +103,7 @@ func (e *encoder) newTypeEncoder(t reflect.Type) encoderFunc { encoder := e.typeEncoder(t.Elem()) return func(key string, value reflect.Value) (pairs []Pair, err error) { if !value.IsValid() || value.IsNil() { - return + return pairs, err } return encoder(key, value.Elem()) } @@ -193,7 +193,7 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc { return func(key string, value reflect.Value) (pairs []Pair, err error) { for _, ef := range encoderFields { - var subkey string = e.renderKeyPath(key, ef.tag.name) + subkey := e.renderKeyPath(key, ef.tag.name) if ef.tag.inline { subkey = key } @@ -205,7 +205,7 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc { } pairs = append(pairs, subpairs...) } - return + return pairs, err } } @@ -256,7 +256,7 @@ func (e *encoder) newMapEncoder(t reflect.Type) encoderFunc { } pairs = append(pairs, subpairs...) } - return + return pairs, err } } @@ -300,7 +300,7 @@ func (e *encoder) newArrayTypeEncoder(t reflect.Type) encoderFunc { } pairs = append(pairs, subpairs...) } - return + return pairs, err } case ArrayQueryFormatIndices: panic("The array indices format is not supported yet") @@ -315,7 +315,7 @@ func (e *encoder) newArrayTypeEncoder(t reflect.Type) encoderFunc { } pairs = append(pairs, subpairs...) } - return + return pairs, err } default: panic(fmt.Sprintf("Unknown ArrayFormat value: %d", e.settings.ArrayFormat)) @@ -372,27 +372,6 @@ func (e *encoder) newPrimitiveTypeEncoder(t reflect.Type) encoderFunc { } } -func (e *encoder) newFieldTypeEncoder(t reflect.Type) encoderFunc { - f, _ := t.FieldByName("Value") - enc := e.typeEncoder(f.Type) - - return func(key string, value reflect.Value) ([]Pair, error) { - present := value.FieldByName("Present") - if !present.Bool() { - return nil, nil - } - null := value.FieldByName("Null") - if null.Bool() { - return nil, fmt.Errorf("apiquery: field cannot be null") - } - raw := value.FieldByName("Raw") - if !raw.IsNil() { - return e.typeEncoder(raw.Type())(key, raw) - } - return enc(key, value.FieldByName("Value")) - } -} - func (e *encoder) newTimeTypeEncoder(_ reflect.Type) encoderFunc { format := e.dateFormat return func(key string, value reflect.Value) ([]Pair, error) { diff --git a/internal/apiquery/tag.go b/internal/apiquery/tag.go index 772c40e..9e413ad 100644 --- a/internal/apiquery/tag.go +++ b/internal/apiquery/tag.go @@ -18,7 +18,7 @@ type parsedStructTag struct { func parseQueryStructTag(field reflect.StructField) (tag parsedStructTag, ok bool) { raw, ok := field.Tag.Lookup(queryStructTag) if !ok { - return + return tag, ok } parts := strings.Split(raw, ",") if len(parts) == 0 { @@ -35,10 +35,10 @@ func parseQueryStructTag(field reflect.StructField) (tag parsedStructTag, ok boo tag.inline = true } } - return + return tag, ok } func parseFormatStructTag(field reflect.StructField) (format string, ok bool) { format, ok = field.Tag.Lookup(formatStructTag) - return + return format, ok } diff --git a/internal/requestconfig/requestconfig.go b/internal/requestconfig/requestconfig.go index 75e05ff..4807d71 100644 --- a/internal/requestconfig/requestconfig.go +++ b/internal/requestconfig/requestconfig.go @@ -121,7 +121,13 @@ func NewRequestConfig(ctx context.Context, method string, u string, body any, ds } params := q.Encode() if params != "" { - u = u + "?" + params + parsed, _ := url.Parse(u) + if parsed.RawQuery != "" { + parsed.RawQuery = parsed.RawQuery + "&" + params + u = parsed.String() + } else { + u = u + "?" + params + } } } if body, ok := body.([]byte); ok { @@ -357,11 +363,9 @@ func (b *bodyWithTimeout) Close() error { } func retryDelay(res *http.Response, retryCount int) time.Duration { - // If the API asks us to wait a certain amount of time (and it's a reasonable amount), - // just do what it says. - - if retryAfterDelay, ok := parseRetryAfterHeader(res); ok && 0 <= retryAfterDelay && retryAfterDelay < time.Minute { - return retryAfterDelay + // If the backend tells us to wait a certain amount of time, use that value + if retryAfterDelay, ok := parseRetryAfterHeader(res); ok { + return max(0, retryAfterDelay) } maxDelay := 8 * time.Second @@ -465,10 +469,14 @@ func (cfg *RequestConfig) Execute() (err error) { // Close the response body before retrying to prevent connection leaks if res != nil && res.Body != nil { - res.Body.Close() + _ = res.Body.Close() } - time.Sleep(retryDelay(res, retryCount)) + select { + case <-ctx.Done(): + return ctx.Err() + case <-time.After(retryDelay(res, retryCount)): + } } // Save *http.Response if it is requested to, even if there was an error making the request. This is @@ -489,7 +497,7 @@ func (cfg *RequestConfig) Execute() (err error) { if res.StatusCode >= 400 { contents, err := io.ReadAll(res.Body) - res.Body.Close() + _ = res.Body.Close() if err != nil { return err } @@ -520,7 +528,7 @@ func (cfg *RequestConfig) Execute() (err error) { } contents, err := io.ReadAll(res.Body) - res.Body.Close() + _ = res.Body.Close() if err != nil { return fmt.Errorf("error reading response body: %w", err) } diff --git a/internal/testutil/testutil.go b/internal/testutil/testutil.go index 826d266..31103e9 100644 --- a/internal/testutil/testutil.go +++ b/internal/testutil/testutil.go @@ -16,10 +16,10 @@ func CheckTestServer(t *testing.T, url string) bool { t.Fatalf("strconv.ParseBool(os.LookupEnv(%s)) failed: %s", SKIP_MOCK_TESTS, err) } if skip { - t.Skip("The test will not run without a mock Prism server running against your OpenAPI spec") + t.Skip("The test will not run without a mock server running against your OpenAPI spec") return false } - t.Errorf("The test will not run without a mock Prism server running against your OpenAPI spec. You can set the environment variable %s to true to skip running any tests that require the mock server", SKIP_MOCK_TESTS) + t.Errorf("The test will not run without a mock server running against your OpenAPI spec. You can set the environment variable %s to true to skip running any tests that require the mock server", SKIP_MOCK_TESTS) return false } } diff --git a/internal/version.go b/internal/version.go index 0759deb..ebb76be 100644 --- a/internal/version.go +++ b/internal/version.go @@ -2,4 +2,4 @@ package internal -const PackageVersion = "2.2.0" // x-release-please-version +const PackageVersion = "2.3.0" // x-release-please-version diff --git a/lib/helper.go b/lib/helper.go index ea38f91..aeae510 100644 --- a/lib/helper.go +++ b/lib/helper.go @@ -618,6 +618,22 @@ func (r *HelperService) processOverlay(overlay shared.OverlayUnionParam) string entries = append(entries, fmt.Sprintf("ly-%s", position.Y.OfString.Value)) } + if !param.IsOmitted(position.XCenter.OfFloat) { + entries = append(entries, fmt.Sprintf("lxc-%g", position.XCenter.OfFloat.Value)) + } else if !param.IsOmitted(position.XCenter.OfString) { + entries = append(entries, fmt.Sprintf("lxc-%s", position.XCenter.OfString.Value)) + } + + if !param.IsOmitted(position.YCenter.OfFloat) { + entries = append(entries, fmt.Sprintf("lyc-%g", position.YCenter.OfFloat.Value)) + } else if !param.IsOmitted(position.YCenter.OfString) { + entries = append(entries, fmt.Sprintf("lyc-%s", position.YCenter.OfString.Value)) + } + + if position.AnchorPoint != "" { + entries = append(entries, fmt.Sprintf("lap-%s", position.AnchorPoint)) + } + if position.Focus != "" { entries = append(entries, fmt.Sprintf("lfo-%s", position.Focus)) } diff --git a/packages/param/encoder.go b/packages/param/encoder.go index b0410be..631e780 100644 --- a/packages/param/encoder.go +++ b/packages/param/encoder.go @@ -83,6 +83,9 @@ func MarshalUnion[T ParamStruct](metadata T, variants ...any) ([]byte, error) { } } if nPresent == 0 || presentIdx == -1 { + if metadata.null() { + return []byte("null"), nil + } if ovr, ok := metadata.Overrides(); ok { return shimjson.Marshal(ovr) } diff --git a/packages/param/encoder_test.go b/packages/param/encoder_test.go index a86612f..eed22a0 100644 --- a/packages/param/encoder_test.go +++ b/packages/param/encoder_test.go @@ -363,3 +363,15 @@ func TestOverriddenUnion(t *testing.T) { }) } } + +func TestNullStructUnion(t *testing.T) { + nullUnion := param.NullStruct[PrimitiveUnion]() + + b, err := json.Marshal(nullUnion) + if err != nil { + t.Fatalf("didn't expect error %v", err) + } + if string(b) != "null" { + t.Fatalf("expected null, received %s", string(b)) + } +} diff --git a/packages/respjson/decoder_test.go b/packages/respjson/decoder_test.go index ef5219c..665a6a8 100644 --- a/packages/respjson/decoder_test.go +++ b/packages/respjson/decoder_test.go @@ -30,7 +30,7 @@ func (r *UnionOfStringIntOrObject) UnmarshalJSON(data []byte) error { type SubFields struct { OfBool bool `json:",inline"` - Name string `json:"name,required"` + Name string `json:"name" api:"required"` JSON struct { OfBool rj.Field Name rj.Field diff --git a/savedextension.go b/savedextension.go index 1999c24..35f38ac 100644 --- a/savedextension.go +++ b/savedextension.go @@ -45,7 +45,7 @@ func (r *SavedExtensionService) New(ctx context.Context, body SavedExtensionNewP opts = slices.Concat(r.Options, opts) path := "v1/saved-extensions" err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...) - return + return res, err } // This API updates an existing saved extension. You can update the name, @@ -54,11 +54,11 @@ func (r *SavedExtensionService) Update(ctx context.Context, id string, body Save opts = slices.Concat(r.Options, opts) if id == "" { err = errors.New("missing required id parameter") - return + return nil, err } path := fmt.Sprintf("v1/saved-extensions/%s", id) err = requestconfig.ExecuteNewRequest(ctx, http.MethodPatch, path, body, &res, opts...) - return + return res, err } // This API returns an array of all saved extensions for your account. Saved @@ -68,7 +68,7 @@ func (r *SavedExtensionService) List(ctx context.Context, opts ...option.Request opts = slices.Concat(r.Options, opts) path := "v1/saved-extensions" err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + return res, err } // This API deletes a saved extension permanently. @@ -77,11 +77,11 @@ func (r *SavedExtensionService) Delete(ctx context.Context, id string, opts ...o opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*")}, opts...) if id == "" { err = errors.New("missing required id parameter") - return + return err } path := fmt.Sprintf("v1/saved-extensions/%s", id) err = requestconfig.ExecuteNewRequest(ctx, http.MethodDelete, path, nil, nil, opts...) - return + return err } // This API returns details of a specific saved extension by ID. @@ -89,21 +89,21 @@ func (r *SavedExtensionService) Get(ctx context.Context, id string, opts ...opti opts = slices.Concat(r.Options, opts) if id == "" { err = errors.New("missing required id parameter") - return + return nil, err } path := fmt.Sprintf("v1/saved-extensions/%s", id) err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...) - return + return res, err } type SavedExtensionNewParams struct { // Configuration object for an extension (base extensions only, not saved extension // references). - Config shared.ExtensionConfigUnionParam `json:"config,omitzero,required"` + Config shared.ExtensionConfigUnionParam `json:"config,omitzero" api:"required"` // Description of what the saved extension does. - Description string `json:"description,required"` + Description string `json:"description" api:"required"` // Name of the saved extension. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` paramObj } diff --git a/savedextension_test.go b/savedextension_test.go index effbeaf..1149d86 100644 --- a/savedextension_test.go +++ b/savedextension_test.go @@ -15,7 +15,7 @@ import ( ) func TestSavedExtensionNewWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -52,7 +52,7 @@ func TestSavedExtensionNewWithOptionalParams(t *testing.T) { } func TestSavedExtensionUpdateWithOptionalParams(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -93,7 +93,7 @@ func TestSavedExtensionUpdateWithOptionalParams(t *testing.T) { } func TestSavedExtensionList(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -117,7 +117,7 @@ func TestSavedExtensionList(t *testing.T) { } func TestSavedExtensionDelete(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -141,7 +141,7 @@ func TestSavedExtensionDelete(t *testing.T) { } func TestSavedExtensionGet(t *testing.T) { - t.Skip("Prism tests are disabled") + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL diff --git a/scripts/mock b/scripts/mock deleted file mode 100755 index 0b28f6e..0000000 --- a/scripts/mock +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd "$(dirname "$0")/.." - -if [[ -n "$1" && "$1" != '--'* ]]; then - URL="$1" - shift -else - URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" -fi - -# Check if the URL is empty -if [ -z "$URL" ]; then - echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" - exit 1 -fi - -echo "==> Starting mock server with URL ${URL}" - -# Run prism mock on the given spec -if [ "$1" == "--daemon" ]; then - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & - - # Wait for server to come online - echo -n "Waiting for server" - while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do - echo -n "." - sleep 0.1 - done - - if grep -q "✖ fatal" ".prism.log"; then - cat .prism.log - exit 1 - fi - - echo -else - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" -fi diff --git a/scripts/test b/scripts/test index c26b122..8704b64 100755 --- a/scripts/test +++ b/scripts/test @@ -4,53 +4,7 @@ set -e cd "$(dirname "$0")/.." -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[0;33m' -NC='\033[0m' # No Color -function prism_is_running() { - curl --silent "http://localhost:4010" >/dev/null 2>&1 -} - -kill_server_on_port() { - pids=$(lsof -t -i tcp:"$1" || echo "") - if [ "$pids" != "" ]; then - kill "$pids" - echo "Stopped $pids." - fi -} - -function is_overriding_api_base_url() { - [ -n "$TEST_API_BASE_URL" ] -} - -if ! is_overriding_api_base_url && ! prism_is_running ; then - # When we exit this script, make sure to kill the background mock server process - trap 'kill_server_on_port 4010' EXIT - - # Start the dev server - ./scripts/mock --daemon -fi - -if is_overriding_api_base_url ; then - echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" - echo -elif ! prism_is_running ; then - echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" - echo -e "running against your OpenAPI spec." - echo - echo -e "To run the server, pass in the path or url of your OpenAPI" - echo -e "spec to the prism command:" - echo - echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" - echo - - exit 1 -else - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" - echo -fi echo "==> Running tests" go test ./... "$@" diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh new file mode 100755 index 0000000..cf87460 --- /dev/null +++ b/scripts/utils/upload-artifact.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -exuo pipefail + +DIST_DIR="dist" +FILENAME="source.zip" + +mapfile -d '' files < <( + find . -type f \ + \( -name '*.go' -o -name 'go.mod' -o -name 'go.sum' \) \ + ! -path "./${DIST_DIR}/*" \ + -print0 +) + +if [[ ${#files[@]} -eq 0 ]]; then + echo -e "\033[31mNo Go source files found for packaging.\033[0m" + exit 1 +fi + +mkdir -p "$DIST_DIR" +rm -f "${DIST_DIR}/${FILENAME}" + +relative_files=() +for file in "${files[@]}"; do + relative_files+=("${file#./}") +done + +zip "${DIST_DIR}/${FILENAME}" "${relative_files[@]}" + +RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + +SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') + +if [[ "$SIGNED_URL" == "null" ]]; then + echo -e "\033[31mFailed to get signed URL.\033[0m" + exit 1 +fi + +UPLOAD_RESPONSE=$(curl -v -X PUT \ + -H "Content-Type: application/zip" \ + --data-binary "@${DIST_DIR}/${FILENAME}" "$SIGNED_URL" 2>&1) + +if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then + echo -e "\033[32mUploaded build to Stainless storage.\033[0m" + echo -e "\033[32mInstallation: Download and unzip: 'https://pkg.stainless.com/s/imagekit-go/$SHA'. Run 'go mod edit -replace github.com/imagekit-developer/imagekit-go/v2=/path/to/unzipped_directory'.\033[0m" +else + echo -e "\033[31mFailed to upload artifact.\033[0m" + exit 1 +fi diff --git a/shared/shared.go b/shared/shared.go index 1d00baa..3699882 100644 --- a/shared/shared.go +++ b/shared/shared.go @@ -155,7 +155,7 @@ func (r ExtensionConfigUnion) ToParam() ExtensionConfigUnionParam { type ExtensionConfigRemoveBg struct { // Specifies the background removal extension. - Name constant.RemoveBg `json:"name,required"` + Name constant.RemoveBg `json:"name" default:"remove-bg"` Options ExtensionConfigRemoveBgOptions `json:"options"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { @@ -205,13 +205,13 @@ func (r *ExtensionConfigRemoveBgOptions) UnmarshalJSON(data []byte) error { type ExtensionConfigAutoTagging struct { // Maximum number of tags to attach to the asset. - MaxTags int64 `json:"maxTags,required"` + MaxTags int64 `json:"maxTags" api:"required"` // Minimum confidence level for tags to be considered valid. - MinConfidence int64 `json:"minConfidence,required"` + MinConfidence int64 `json:"minConfidence" api:"required"` // Specifies the auto-tagging extension used. // // Any of "google-auto-tagging", "aws-auto-tagging". - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { MaxTags respjson.Field @@ -230,7 +230,7 @@ func (r *ExtensionConfigAutoTagging) UnmarshalJSON(data []byte) error { type ExtensionConfigAIAutoDescription struct { // Specifies the auto description extension. - Name constant.AIAutoDescription `json:"name,required"` + Name constant.AIAutoDescription `json:"name" default:"ai-auto-description"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Name respjson.Field @@ -247,9 +247,9 @@ func (r *ExtensionConfigAIAutoDescription) UnmarshalJSON(data []byte) error { type ExtensionConfigAITasks struct { // Specifies the AI tasks extension for automated image analysis using AI models. - Name constant.AITasks `json:"name,required"` + Name constant.AITasks `json:"name" default:"ai-tasks"` // Array of task objects defining AI operations to perform on the asset. - Tasks []ExtensionConfigAITasksTaskUnion `json:"tasks,required"` + Tasks []ExtensionConfigAITasksTaskUnion `json:"tasks" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Name respjson.Field @@ -383,15 +383,17 @@ func (r *ExtensionConfigAITasksTaskUnionVocabulary) UnmarshalJSON(data []byte) e type ExtensionConfigAITasksTaskSelectTags struct { // The question or instruction for the AI to analyze the image. - Instruction string `json:"instruction,required"` + Instruction string `json:"instruction" api:"required"` // Task type that analyzes the image and adds matching tags from a vocabulary. - Type constant.SelectTags `json:"type,required"` + Type constant.SelectTags `json:"type" default:"select_tags"` // Maximum number of tags to select from the vocabulary. MaxSelections int64 `json:"max_selections"` // Minimum number of tags to select from the vocabulary. MinSelections int64 `json:"min_selections"` - // Array of possible tag values. Combined length of all strings must not exceed 500 - // characters. Cannot contain the `%` character. + // Array of possible tag values. The combined length of all strings must not exceed + // 500 characters, and values cannot include the `%` character. When providing + // large vocabularies (more than 30 items), the AI may not follow the list + // strictly. Vocabulary []string `json:"vocabulary"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { @@ -415,17 +417,20 @@ func (ExtensionConfigAITasksTaskSelectTags) implExtensionConfigAITasksTaskUnion( type ExtensionConfigAITasksTaskSelectMetadata struct { // Name of the custom metadata field to set. The field must exist in your account. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // The question or instruction for the AI to analyze the image. - Instruction string `json:"instruction,required"` + Instruction string `json:"instruction" api:"required"` // Task type that analyzes the image and sets a custom metadata field value from a // vocabulary. - Type constant.SelectMetadata `json:"type,required"` + Type constant.SelectMetadata `json:"type" default:"select_metadata"` // Maximum number of values to select from the vocabulary. MaxSelections int64 `json:"max_selections"` // Minimum number of values to select from the vocabulary. MinSelections int64 `json:"min_selections"` - // Array of possible values matching the custom metadata field type. + // An array of possible values matching the custom metadata field type. If not + // provided for SingleSelect or MultiSelect field types, all values from the custom + // metadata field definition will be used. When providing large vocabularies (above + // 30 items), the AI may not strictly adhere to the list. Vocabulary []ExtensionConfigAITasksTaskSelectMetadataVocabularyUnion `json:"vocabulary"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { @@ -494,9 +499,9 @@ func (r *ExtensionConfigAITasksTaskSelectMetadataVocabularyUnion) UnmarshalJSON( type ExtensionConfigAITasksTaskYesNo struct { // The yes/no question for the AI to answer about the image. - Instruction string `json:"instruction,required"` + Instruction string `json:"instruction" api:"required"` // Task type that asks a yes/no question and executes actions based on the answer. - Type constant.YesNo `json:"type,required"` + Type constant.YesNo `json:"type" default:"yes_no"` // Actions to execute if the AI answers no. OnNo ExtensionConfigAITasksTaskYesNoOnNo `json:"on_no"` // Actions to execute if the AI cannot determine the answer. @@ -552,10 +557,10 @@ func (r *ExtensionConfigAITasksTaskYesNoOnNo) UnmarshalJSON(data []byte) error { type ExtensionConfigAITasksTaskYesNoOnNoSetMetadata struct { // Name of the custom metadata field to set. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // Value to set for the custom metadata field. The value type should match the // custom metadata field type. - Value ExtensionConfigAITasksTaskYesNoOnNoSetMetadataValueUnion `json:"value,required"` + Value ExtensionConfigAITasksTaskYesNoOnNoSetMetadataValueUnion `json:"value" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Field respjson.Field @@ -674,7 +679,7 @@ func (r *ExtensionConfigAITasksTaskYesNoOnNoSetMetadataValueMixedItemUnion) Unma type ExtensionConfigAITasksTaskYesNoOnNoUnsetMetadata struct { // Name of the custom metadata field to remove. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Field respjson.Field @@ -718,10 +723,10 @@ func (r *ExtensionConfigAITasksTaskYesNoOnUnknown) UnmarshalJSON(data []byte) er type ExtensionConfigAITasksTaskYesNoOnUnknownSetMetadata struct { // Name of the custom metadata field to set. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // Value to set for the custom metadata field. The value type should match the // custom metadata field type. - Value ExtensionConfigAITasksTaskYesNoOnUnknownSetMetadataValueUnion `json:"value,required"` + Value ExtensionConfigAITasksTaskYesNoOnUnknownSetMetadataValueUnion `json:"value" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Field respjson.Field @@ -842,7 +847,7 @@ func (r *ExtensionConfigAITasksTaskYesNoOnUnknownSetMetadataValueMixedItemUnion) type ExtensionConfigAITasksTaskYesNoOnUnknownUnsetMetadata struct { // Name of the custom metadata field to remove. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Field respjson.Field @@ -886,10 +891,10 @@ func (r *ExtensionConfigAITasksTaskYesNoOnYes) UnmarshalJSON(data []byte) error type ExtensionConfigAITasksTaskYesNoOnYesSetMetadata struct { // Name of the custom metadata field to set. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // Value to set for the custom metadata field. The value type should match the // custom metadata field type. - Value ExtensionConfigAITasksTaskYesNoOnYesSetMetadataValueUnion `json:"value,required"` + Value ExtensionConfigAITasksTaskYesNoOnYesSetMetadataValueUnion `json:"value" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Field respjson.Field @@ -1010,7 +1015,7 @@ func (r *ExtensionConfigAITasksTaskYesNoOnYesSetMetadataValueMixedItemUnion) Unm type ExtensionConfigAITasksTaskYesNoOnYesUnsetMetadata struct { // Name of the custom metadata field to remove. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Field respjson.Field @@ -1133,7 +1138,7 @@ type ExtensionConfigRemoveBgParam struct { // Specifies the background removal extension. // // This field can be elided, and will marshal its zero value as "remove-bg". - Name constant.RemoveBg `json:"name,required"` + Name constant.RemoveBg `json:"name" default:"remove-bg"` paramObj } @@ -1173,13 +1178,13 @@ func (r *ExtensionConfigRemoveBgOptionsParam) UnmarshalJSON(data []byte) error { // The properties MaxTags, MinConfidence, Name are required. type ExtensionConfigAutoTaggingParam struct { // Maximum number of tags to attach to the asset. - MaxTags int64 `json:"maxTags,required"` + MaxTags int64 `json:"maxTags" api:"required"` // Minimum confidence level for tags to be considered valid. - MinConfidence int64 `json:"minConfidence,required"` + MinConfidence int64 `json:"minConfidence" api:"required"` // Specifies the auto-tagging extension used. // // Any of "google-auto-tagging", "aws-auto-tagging". - Name string `json:"name,omitzero,required"` + Name string `json:"name,omitzero" api:"required"` paramObj } @@ -1207,7 +1212,7 @@ func NewExtensionConfigAIAutoDescriptionParam() ExtensionConfigAIAutoDescription // [NewExtensionConfigAIAutoDescriptionParam]. type ExtensionConfigAIAutoDescriptionParam struct { // Specifies the auto description extension. - Name constant.AIAutoDescription `json:"name,required"` + Name constant.AIAutoDescription `json:"name" default:"ai-auto-description"` paramObj } @@ -1222,11 +1227,11 @@ func (r *ExtensionConfigAIAutoDescriptionParam) UnmarshalJSON(data []byte) error // The properties Name, Tasks are required. type ExtensionConfigAITasksParam struct { // Array of task objects defining AI operations to perform on the asset. - Tasks []ExtensionConfigAITasksTaskUnionParam `json:"tasks,omitzero,required"` + Tasks []ExtensionConfigAITasksTaskUnionParam `json:"tasks,omitzero" api:"required"` // Specifies the AI tasks extension for automated image analysis using AI models. // // This field can be elided, and will marshal its zero value as "ai-tasks". - Name constant.AITasks `json:"name,required"` + Name constant.AITasks `json:"name" default:"ai-tasks"` paramObj } @@ -1380,18 +1385,20 @@ func init() { // The properties Instruction, Type are required. type ExtensionConfigAITasksTaskSelectTagsParam struct { // The question or instruction for the AI to analyze the image. - Instruction string `json:"instruction,required"` + Instruction string `json:"instruction" api:"required"` // Maximum number of tags to select from the vocabulary. MaxSelections param.Opt[int64] `json:"max_selections,omitzero"` // Minimum number of tags to select from the vocabulary. MinSelections param.Opt[int64] `json:"min_selections,omitzero"` - // Array of possible tag values. Combined length of all strings must not exceed 500 - // characters. Cannot contain the `%` character. + // Array of possible tag values. The combined length of all strings must not exceed + // 500 characters, and values cannot include the `%` character. When providing + // large vocabularies (more than 30 items), the AI may not follow the list + // strictly. Vocabulary []string `json:"vocabulary,omitzero"` // Task type that analyzes the image and adds matching tags from a vocabulary. // // This field can be elided, and will marshal its zero value as "select_tags". - Type constant.SelectTags `json:"type,required"` + Type constant.SelectTags `json:"type" default:"select_tags"` paramObj } @@ -1406,20 +1413,23 @@ func (r *ExtensionConfigAITasksTaskSelectTagsParam) UnmarshalJSON(data []byte) e // The properties Field, Instruction, Type are required. type ExtensionConfigAITasksTaskSelectMetadataParam struct { // Name of the custom metadata field to set. The field must exist in your account. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // The question or instruction for the AI to analyze the image. - Instruction string `json:"instruction,required"` + Instruction string `json:"instruction" api:"required"` // Maximum number of values to select from the vocabulary. MaxSelections param.Opt[int64] `json:"max_selections,omitzero"` // Minimum number of values to select from the vocabulary. MinSelections param.Opt[int64] `json:"min_selections,omitzero"` - // Array of possible values matching the custom metadata field type. + // An array of possible values matching the custom metadata field type. If not + // provided for SingleSelect or MultiSelect field types, all values from the custom + // metadata field definition will be used. When providing large vocabularies (above + // 30 items), the AI may not strictly adhere to the list. Vocabulary []ExtensionConfigAITasksTaskSelectMetadataVocabularyUnionParam `json:"vocabulary,omitzero"` // Task type that analyzes the image and sets a custom metadata field value from a // vocabulary. // // This field can be elided, and will marshal its zero value as "select_metadata". - Type constant.SelectMetadata `json:"type,required"` + Type constant.SelectMetadata `json:"type" default:"select_metadata"` paramObj } @@ -1462,7 +1472,7 @@ func (u *ExtensionConfigAITasksTaskSelectMetadataVocabularyUnionParam) asAny() a // The properties Instruction, Type are required. type ExtensionConfigAITasksTaskYesNoParam struct { // The yes/no question for the AI to answer about the image. - Instruction string `json:"instruction,required"` + Instruction string `json:"instruction" api:"required"` // Actions to execute if the AI answers no. OnNo ExtensionConfigAITasksTaskYesNoOnNoParam `json:"on_no,omitzero"` // Actions to execute if the AI cannot determine the answer. @@ -1472,7 +1482,7 @@ type ExtensionConfigAITasksTaskYesNoParam struct { // Task type that asks a yes/no question and executes actions based on the answer. // // This field can be elided, and will marshal its zero value as "yes_no". - Type constant.YesNo `json:"type,required"` + Type constant.YesNo `json:"type" default:"yes_no"` paramObj } @@ -1508,10 +1518,10 @@ func (r *ExtensionConfigAITasksTaskYesNoOnNoParam) UnmarshalJSON(data []byte) er // The properties Field, Value are required. type ExtensionConfigAITasksTaskYesNoOnNoSetMetadataParam struct { // Name of the custom metadata field to set. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // Value to set for the custom metadata field. The value type should match the // custom metadata field type. - Value ExtensionConfigAITasksTaskYesNoOnNoSetMetadataValueUnionParam `json:"value,omitzero,required"` + Value ExtensionConfigAITasksTaskYesNoOnNoSetMetadataValueUnionParam `json:"value,omitzero" api:"required"` paramObj } @@ -1585,7 +1595,7 @@ func (u *ExtensionConfigAITasksTaskYesNoOnNoSetMetadataValueMixedItemUnionParam) // The property Field is required. type ExtensionConfigAITasksTaskYesNoOnNoUnsetMetadataParam struct { // Name of the custom metadata field to remove. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` paramObj } @@ -1621,10 +1631,10 @@ func (r *ExtensionConfigAITasksTaskYesNoOnUnknownParam) UnmarshalJSON(data []byt // The properties Field, Value are required. type ExtensionConfigAITasksTaskYesNoOnUnknownSetMetadataParam struct { // Name of the custom metadata field to set. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // Value to set for the custom metadata field. The value type should match the // custom metadata field type. - Value ExtensionConfigAITasksTaskYesNoOnUnknownSetMetadataValueUnionParam `json:"value,omitzero,required"` + Value ExtensionConfigAITasksTaskYesNoOnUnknownSetMetadataValueUnionParam `json:"value,omitzero" api:"required"` paramObj } @@ -1698,7 +1708,7 @@ func (u *ExtensionConfigAITasksTaskYesNoOnUnknownSetMetadataValueMixedItemUnionP // The property Field is required. type ExtensionConfigAITasksTaskYesNoOnUnknownUnsetMetadataParam struct { // Name of the custom metadata field to remove. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` paramObj } @@ -1734,10 +1744,10 @@ func (r *ExtensionConfigAITasksTaskYesNoOnYesParam) UnmarshalJSON(data []byte) e // The properties Field, Value are required. type ExtensionConfigAITasksTaskYesNoOnYesSetMetadataParam struct { // Name of the custom metadata field to set. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // Value to set for the custom metadata field. The value type should match the // custom metadata field type. - Value ExtensionConfigAITasksTaskYesNoOnYesSetMetadataValueUnionParam `json:"value,omitzero,required"` + Value ExtensionConfigAITasksTaskYesNoOnYesSetMetadataValueUnionParam `json:"value,omitzero" api:"required"` paramObj } @@ -1811,7 +1821,7 @@ func (u *ExtensionConfigAITasksTaskYesNoOnYesSetMetadataValueMixedItemUnionParam // The property Field is required. type ExtensionConfigAITasksTaskYesNoOnYesUnsetMetadataParam struct { // Name of the custom metadata field to remove. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` paramObj } @@ -1937,7 +1947,7 @@ type ExtensionRemoveBgParam struct { // Specifies the background removal extension. // // This field can be elided, and will marshal its zero value as "remove-bg". - Name constant.RemoveBg `json:"name,required"` + Name constant.RemoveBg `json:"name" default:"remove-bg"` paramObj } @@ -1977,13 +1987,13 @@ func (r *ExtensionRemoveBgOptionsParam) UnmarshalJSON(data []byte) error { // The properties MaxTags, MinConfidence, Name are required. type ExtensionAutoTaggingParam struct { // Maximum number of tags to attach to the asset. - MaxTags int64 `json:"maxTags,required"` + MaxTags int64 `json:"maxTags" api:"required"` // Minimum confidence level for tags to be considered valid. - MinConfidence int64 `json:"minConfidence,required"` + MinConfidence int64 `json:"minConfidence" api:"required"` // Specifies the auto-tagging extension used. // // Any of "google-auto-tagging", "aws-auto-tagging". - Name string `json:"name,omitzero,required"` + Name string `json:"name,omitzero" api:"required"` paramObj } @@ -2011,7 +2021,7 @@ func NewExtensionAIAutoDescriptionParam() ExtensionAIAutoDescriptionParam { // [NewExtensionAIAutoDescriptionParam]. type ExtensionAIAutoDescriptionParam struct { // Specifies the auto description extension. - Name constant.AIAutoDescription `json:"name,required"` + Name constant.AIAutoDescription `json:"name" default:"ai-auto-description"` paramObj } @@ -2026,11 +2036,11 @@ func (r *ExtensionAIAutoDescriptionParam) UnmarshalJSON(data []byte) error { // The properties Name, Tasks are required. type ExtensionAITasksParam struct { // Array of task objects defining AI operations to perform on the asset. - Tasks []ExtensionAITasksTaskUnionParam `json:"tasks,omitzero,required"` + Tasks []ExtensionAITasksTaskUnionParam `json:"tasks,omitzero" api:"required"` // Specifies the AI tasks extension for automated image analysis using AI models. // // This field can be elided, and will marshal its zero value as "ai-tasks". - Name constant.AITasks `json:"name,required"` + Name constant.AITasks `json:"name" default:"ai-tasks"` paramObj } @@ -2184,18 +2194,20 @@ func init() { // The properties Instruction, Type are required. type ExtensionAITasksTaskSelectTagsParam struct { // The question or instruction for the AI to analyze the image. - Instruction string `json:"instruction,required"` + Instruction string `json:"instruction" api:"required"` // Maximum number of tags to select from the vocabulary. MaxSelections param.Opt[int64] `json:"max_selections,omitzero"` // Minimum number of tags to select from the vocabulary. MinSelections param.Opt[int64] `json:"min_selections,omitzero"` - // Array of possible tag values. Combined length of all strings must not exceed 500 - // characters. Cannot contain the `%` character. + // Array of possible tag values. The combined length of all strings must not exceed + // 500 characters, and values cannot include the `%` character. When providing + // large vocabularies (more than 30 items), the AI may not follow the list + // strictly. Vocabulary []string `json:"vocabulary,omitzero"` // Task type that analyzes the image and adds matching tags from a vocabulary. // // This field can be elided, and will marshal its zero value as "select_tags". - Type constant.SelectTags `json:"type,required"` + Type constant.SelectTags `json:"type" default:"select_tags"` paramObj } @@ -2210,20 +2222,23 @@ func (r *ExtensionAITasksTaskSelectTagsParam) UnmarshalJSON(data []byte) error { // The properties Field, Instruction, Type are required. type ExtensionAITasksTaskSelectMetadataParam struct { // Name of the custom metadata field to set. The field must exist in your account. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // The question or instruction for the AI to analyze the image. - Instruction string `json:"instruction,required"` + Instruction string `json:"instruction" api:"required"` // Maximum number of values to select from the vocabulary. MaxSelections param.Opt[int64] `json:"max_selections,omitzero"` // Minimum number of values to select from the vocabulary. MinSelections param.Opt[int64] `json:"min_selections,omitzero"` - // Array of possible values matching the custom metadata field type. + // An array of possible values matching the custom metadata field type. If not + // provided for SingleSelect or MultiSelect field types, all values from the custom + // metadata field definition will be used. When providing large vocabularies (above + // 30 items), the AI may not strictly adhere to the list. Vocabulary []ExtensionAITasksTaskSelectMetadataVocabularyUnionParam `json:"vocabulary,omitzero"` // Task type that analyzes the image and sets a custom metadata field value from a // vocabulary. // // This field can be elided, and will marshal its zero value as "select_metadata". - Type constant.SelectMetadata `json:"type,required"` + Type constant.SelectMetadata `json:"type" default:"select_metadata"` paramObj } @@ -2266,7 +2281,7 @@ func (u *ExtensionAITasksTaskSelectMetadataVocabularyUnionParam) asAny() any { // The properties Instruction, Type are required. type ExtensionAITasksTaskYesNoParam struct { // The yes/no question for the AI to answer about the image. - Instruction string `json:"instruction,required"` + Instruction string `json:"instruction" api:"required"` // Actions to execute if the AI answers no. OnNo ExtensionAITasksTaskYesNoOnNoParam `json:"on_no,omitzero"` // Actions to execute if the AI cannot determine the answer. @@ -2276,7 +2291,7 @@ type ExtensionAITasksTaskYesNoParam struct { // Task type that asks a yes/no question and executes actions based on the answer. // // This field can be elided, and will marshal its zero value as "yes_no". - Type constant.YesNo `json:"type,required"` + Type constant.YesNo `json:"type" default:"yes_no"` paramObj } @@ -2312,10 +2327,10 @@ func (r *ExtensionAITasksTaskYesNoOnNoParam) UnmarshalJSON(data []byte) error { // The properties Field, Value are required. type ExtensionAITasksTaskYesNoOnNoSetMetadataParam struct { // Name of the custom metadata field to set. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // Value to set for the custom metadata field. The value type should match the // custom metadata field type. - Value ExtensionAITasksTaskYesNoOnNoSetMetadataValueUnionParam `json:"value,omitzero,required"` + Value ExtensionAITasksTaskYesNoOnNoSetMetadataValueUnionParam `json:"value,omitzero" api:"required"` paramObj } @@ -2389,7 +2404,7 @@ func (u *ExtensionAITasksTaskYesNoOnNoSetMetadataValueMixedItemUnionParam) asAny // The property Field is required. type ExtensionAITasksTaskYesNoOnNoUnsetMetadataParam struct { // Name of the custom metadata field to remove. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` paramObj } @@ -2425,10 +2440,10 @@ func (r *ExtensionAITasksTaskYesNoOnUnknownParam) UnmarshalJSON(data []byte) err // The properties Field, Value are required. type ExtensionAITasksTaskYesNoOnUnknownSetMetadataParam struct { // Name of the custom metadata field to set. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // Value to set for the custom metadata field. The value type should match the // custom metadata field type. - Value ExtensionAITasksTaskYesNoOnUnknownSetMetadataValueUnionParam `json:"value,omitzero,required"` + Value ExtensionAITasksTaskYesNoOnUnknownSetMetadataValueUnionParam `json:"value,omitzero" api:"required"` paramObj } @@ -2502,7 +2517,7 @@ func (u *ExtensionAITasksTaskYesNoOnUnknownSetMetadataValueMixedItemUnionParam) // The property Field is required. type ExtensionAITasksTaskYesNoOnUnknownUnsetMetadataParam struct { // Name of the custom metadata field to remove. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` paramObj } @@ -2538,10 +2553,10 @@ func (r *ExtensionAITasksTaskYesNoOnYesParam) UnmarshalJSON(data []byte) error { // The properties Field, Value are required. type ExtensionAITasksTaskYesNoOnYesSetMetadataParam struct { // Name of the custom metadata field to set. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` // Value to set for the custom metadata field. The value type should match the // custom metadata field type. - Value ExtensionAITasksTaskYesNoOnYesSetMetadataValueUnionParam `json:"value,omitzero,required"` + Value ExtensionAITasksTaskYesNoOnYesSetMetadataValueUnionParam `json:"value,omitzero" api:"required"` paramObj } @@ -2615,7 +2630,7 @@ func (u *ExtensionAITasksTaskYesNoOnYesSetMetadataValueMixedItemUnionParam) asAn // The property Field is required. type ExtensionAITasksTaskYesNoOnYesUnsetMetadataParam struct { // Name of the custom metadata field to remove. - Field string `json:"field,required"` + Field string `json:"field" api:"required"` paramObj } @@ -2630,11 +2645,11 @@ func (r *ExtensionAITasksTaskYesNoOnYesUnsetMetadataParam) UnmarshalJSON(data [] // The properties ID, Name are required. type ExtensionSavedExtensionParam struct { // The unique ID of the saved extension to apply. - ID string `json:"id,required"` + ID string `json:"id" api:"required"` // Indicates this is a reference to a saved extension. // // This field can be elided, and will marshal its zero value as "saved-extension". - Name constant.SavedExtension `json:"name,required"` + Name constant.SavedExtension `json:"name" default:"saved-extension"` paramObj } @@ -2692,8 +2707,8 @@ func (r GetImageAttributesOptionsParam) MarshalJSON() (data []byte, err error) { type ImageOverlayParam struct { // Specifies the relative path to the image used as an overlay. - Input string `json:"input,required"` - Type constant.Image `json:"type,required"` + Input string `json:"input" api:"required"` + Type constant.Image `json:"type" default:"image"` // The input path can be included in the layer as either `i-{input}` or // `ie-{base64_encoded_input}`. By default, the SDK determines the appropriate // format automatically. To always use base64 encoding (`ie-{base64}`), set this @@ -2944,8 +2959,16 @@ func init() { } type OverlayPositionParam struct { - // Specifies the position of the overlay relative to the parent image or video. - // Maps to `lfo` in the URL. + // Sets the anchor point on the base asset from which the overlay offset is + // calculated. The default value is `top_left`. Maps to `lap` in the URL. Can only + // be used with one or more of `x`, `y`, `xCenter`, or `yCenter`. + // + // Any of "top", "left", "right", "bottom", "top_left", "top_right", "bottom_left", + // "bottom_right", "center". + AnchorPoint OverlayPositionAnchorPoint `json:"anchorPoint,omitzero"` + // Specifies the position of the overlay relative to the parent image or video. If + // one or more of `x`, `y`, `xCenter`, or `yCenter` parameters are specified, this + // parameter is ignored. Maps to `lfo` in the URL. // // Any of "center", "top", "left", "bottom", "right", "top_left", "top_right", // "bottom_left", "bottom_right". @@ -2956,12 +2979,24 @@ type OverlayPositionParam struct { // about // [Arithmetic expressions](https://imagekit.io/docs/arithmetic-expressions-in-transformations). X OverlayPositionXUnionParam `json:"x,omitzero"` + // Specifies the x-coordinate on the base asset where the overlay's center will be + // positioned. It also accepts arithmetic expressions such as `bw_mul_0.4` or + // `bw_sub_cw`. Maps to `lxc` in the URL. Cannot be used together with `x`, but can + // be used with `y`. Learn about + // [Arithmetic expressions](https://imagekit.io/docs/arithmetic-expressions-in-transformations). + XCenter OverlayPositionXCenterUnionParam `json:"xCenter,omitzero"` // Specifies the y-coordinate of the top-left corner of the base asset where the // overlay's top-left corner will be positioned. It also accepts arithmetic // expressions such as `bh_mul_0.4` or `bh_sub_ch`. Maps to `ly` in the URL. Learn // about // [Arithmetic expressions](https://imagekit.io/docs/arithmetic-expressions-in-transformations). Y OverlayPositionYUnionParam `json:"y,omitzero"` + // Specifies the y-coordinate on the base asset where the overlay's center will be + // positioned. It also accepts arithmetic expressions such as `bh_mul_0.4` or + // `bh_sub_ch`. Maps to `lyc` in the URL. Cannot be used together with `y`, but can + // be used with `x`. Learn about + // [Arithmetic expressions](https://imagekit.io/docs/arithmetic-expressions-in-transformations). + YCenter OverlayPositionYCenterUnionParam `json:"yCenter,omitzero"` paramObj } @@ -2973,8 +3008,26 @@ func (r *OverlayPositionParam) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) } -// Specifies the position of the overlay relative to the parent image or video. -// Maps to `lfo` in the URL. +// Sets the anchor point on the base asset from which the overlay offset is +// calculated. The default value is `top_left`. Maps to `lap` in the URL. Can only +// be used with one or more of `x`, `y`, `xCenter`, or `yCenter`. +type OverlayPositionAnchorPoint string + +const ( + OverlayPositionAnchorPointTop OverlayPositionAnchorPoint = "top" + OverlayPositionAnchorPointLeft OverlayPositionAnchorPoint = "left" + OverlayPositionAnchorPointRight OverlayPositionAnchorPoint = "right" + OverlayPositionAnchorPointBottom OverlayPositionAnchorPoint = "bottom" + OverlayPositionAnchorPointTopLeft OverlayPositionAnchorPoint = "top_left" + OverlayPositionAnchorPointTopRight OverlayPositionAnchorPoint = "top_right" + OverlayPositionAnchorPointBottomLeft OverlayPositionAnchorPoint = "bottom_left" + OverlayPositionAnchorPointBottomRight OverlayPositionAnchorPoint = "bottom_right" + OverlayPositionAnchorPointCenter OverlayPositionAnchorPoint = "center" +) + +// Specifies the position of the overlay relative to the parent image or video. If +// one or more of `x`, `y`, `xCenter`, or `yCenter` parameters are specified, this +// parameter is ignored. Maps to `lfo` in the URL. type OverlayPositionFocus string const ( @@ -3014,6 +3067,31 @@ func (u *OverlayPositionXUnionParam) asAny() any { return nil } +// Only one field can be non-zero. +// +// Use [param.IsOmitted] to confirm if a field is set. +type OverlayPositionXCenterUnionParam struct { + OfFloat param.Opt[float64] `json:",omitzero,inline"` + OfString param.Opt[string] `json:",omitzero,inline"` + paramUnion +} + +func (u OverlayPositionXCenterUnionParam) MarshalJSON() ([]byte, error) { + return param.MarshalUnion(u, u.OfFloat, u.OfString) +} +func (u *OverlayPositionXCenterUnionParam) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, u) +} + +func (u *OverlayPositionXCenterUnionParam) asAny() any { + if !param.IsOmitted(u.OfFloat) { + return &u.OfFloat.Value + } else if !param.IsOmitted(u.OfString) { + return &u.OfString.Value + } + return nil +} + // Only one field can be non-zero. // // Use [param.IsOmitted] to confirm if a field is set. @@ -3039,6 +3117,31 @@ func (u *OverlayPositionYUnionParam) asAny() any { return nil } +// Only one field can be non-zero. +// +// Use [param.IsOmitted] to confirm if a field is set. +type OverlayPositionYCenterUnionParam struct { + OfFloat param.Opt[float64] `json:",omitzero,inline"` + OfString param.Opt[string] `json:",omitzero,inline"` + paramUnion +} + +func (u OverlayPositionYCenterUnionParam) MarshalJSON() ([]byte, error) { + return param.MarshalUnion(u, u.OfFloat, u.OfString) +} +func (u *OverlayPositionYCenterUnionParam) UnmarshalJSON(data []byte) error { + return apijson.UnmarshalRoot(data, u) +} + +func (u *OverlayPositionYCenterUnionParam) asAny() any { + if !param.IsOmitted(u.OfFloat) { + return &u.OfFloat.Value + } else if !param.IsOmitted(u.OfString) { + return &u.OfString.Value + } + return nil +} + type OverlayTimingParam struct { // Specifies the duration (in seconds) during which the overlay should appear on // the base video. Accepts a positive number up to two decimal places (e.g., `20` @@ -3148,7 +3251,7 @@ func (u *OverlayTimingStartUnionParam) asAny() any { // The property Src is required. type ResponsiveImageAttributesParam struct { // URL for the _largest_ candidate (assigned to plain `src`). - Src string `json:"src,required" format:"uri"` + Src string `json:"src" api:"required" format:"uri"` // `sizes` returned (or synthesised as `100vw`). The value for the HTML `sizes` // attribute. Sizes param.Opt[string] `json:"sizes,omitzero"` @@ -3242,8 +3345,8 @@ type SolidColorOverlayParam struct { // code (e.g., `FFAABB50`), or a color name (e.g., `red`). If an 8-character value // is provided, the last two characters represent the opacity level (from `00` for // 0.00 to `99` for 0.99). - Color string `json:"color,required"` - Type constant.SolidColor `json:"type,required"` + Color string `json:"color" api:"required"` + Type constant.SolidColor `json:"type" default:"solidColor"` // Control width and height of the solid color overlay. Supported transformations // depend on the base/parent asset. See overlays on // [Images](https://imagekit.io/docs/add-overlays-on-images#apply-transformation-on-solid-color-overlay) @@ -3420,10 +3523,10 @@ type SrcOptionsParam struct { // Accepts a relative or absolute path of the resource. If a relative path is // provided, it is appended to the `urlEndpoint`. If an absolute path is provided, // `urlEndpoint` is ignored. - Src string `json:"src,required"` + Src string `json:"src" api:"required"` // Get your urlEndpoint from the // [ImageKit dashboard](https://imagekit.io/dashboard/url-endpoints). - URLEndpoint string `json:"urlEndpoint,required" format:"uri"` + URLEndpoint string `json:"urlEndpoint" api:"required" format:"uri"` // When you want the signed URL to expire, specified in seconds. If `expiresIn` is // anything above 0, the URL will always be signed even if `signed` is set to // false. If not specified and `signed` is `true`, the signed URL will not expire @@ -3484,8 +3587,8 @@ const ( type SubtitleOverlayParam struct { // Specifies the relative path to the subtitle file used as an overlay. - Input string `json:"input,required"` - Type constant.Subtitle `json:"type,required"` + Input string `json:"input" api:"required"` + Type constant.Subtitle `json:"type" default:"subtitle"` // The input path can be included in the layer as either `i-{input}` or // `ie-{base64_encoded_input}`. By default, the SDK determines the appropriate // format automatically. To always use base64 encoding (`ie-{base64}`), set this @@ -3584,8 +3687,8 @@ const ( type TextOverlayParam struct { // Specifies the text to be displayed in the overlay. The SDK automatically handles // special characters and encoding. - Text string `json:"text,required"` - Type constant.Text `json:"type,required"` + Text string `json:"text" api:"required"` + Type constant.Text `json:"type" default:"text"` // Text can be included in the layer as either `i-{input}` (plain text) or // `ie-{base64_encoded_input}` (base64). By default, the SDK selects the // appropriate format based on the input text. To always use base64 @@ -4805,8 +4908,8 @@ const ( type VideoOverlayParam struct { // Specifies the relative path to the video used as an overlay. - Input string `json:"input,required"` - Type constant.Video `json:"type,required"` + Input string `json:"input" api:"required"` + Type constant.Video `json:"type" default:"video"` // The input path can be included in the layer as either `i-{input}` or // `ie-{base64_encoded_input}`. By default, the SDK determines the appropriate // format automatically. To always use base64 encoding (`ie-{base64}`), set this diff --git a/tests/helper_overlay_test.go b/tests/helper_overlay_test.go index 4e730d1..ace80d8 100644 --- a/tests/helper_overlay_test.go +++ b/tests/helper_overlay_test.go @@ -945,4 +945,36 @@ func TestOverlayEncoding(t *testing.T) { t.Errorf("Expected %s, got %s", expected, url) } }) + + t.Run("should generate URL with image overlay using xCenter yCenter and anchorPoint", func(t *testing.T) { + transformation := []shared.TransformationParam{ + { + Overlay: shared.OverlayUnionParam{ + OfImage: &shared.ImageOverlayParam{ + Input: "logo.png", + Type: constant.Image("image"), + BaseOverlayParam: shared.BaseOverlayParam{ + Position: shared.OverlayPositionParam{ + XCenter: shared.OverlayPositionXCenterUnionParam{OfFloat: param.Opt[float64]{Value: 50}}, + YCenter: shared.OverlayPositionYCenterUnionParam{OfString: param.Opt[string]{Value: "bh_mul_0.5"}}, + AnchorPoint: shared.OverlayPositionAnchorPointTopLeft, + }, + }, + }, + }, + }, + } + + url := client.Helper.BuildURL(shared.SrcOptionsParam{ + URLEndpoint: "https://ik.imagekit.io/test_url_endpoint", + TransformationPosition: shared.TransformationPositionPath, + Src: "/base-image.jpg", + Transformation: transformation, + }) + + expected := "https://ik.imagekit.io/test_url_endpoint/tr:l-image,i-logo.png,lxc-50,lyc-bh_mul_0.5,lap-top_left,l-end/base-image.jpg" + if url != expected { + t.Errorf("Expected %s, got %s", expected, url) + } + }) } diff --git a/usage_test.go b/usage_test.go index 6792db9..9f1ec4a 100644 --- a/usage_test.go +++ b/usage_test.go @@ -15,6 +15,7 @@ import ( ) func TestUsage(t *testing.T) { + t.Skip("Mock server tests are disabled") baseURL := "http://localhost:4010" if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok { baseURL = envURL @@ -27,7 +28,6 @@ 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 abddde8..d49e2ac 100644 --- a/webhook.go +++ b/webhook.go @@ -75,9 +75,9 @@ func (r *WebhookService) Unwrap(payload []byte, headers http.Header, opts ...opt type BaseWebhookEvent struct { // Unique identifier for the event. - ID string `json:"id,required"` + ID string `json:"id" api:"required"` // The type of webhook event. - Type string `json:"type,required"` + Type string `json:"type" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { ID respjson.Field @@ -97,10 +97,10 @@ func (r *BaseWebhookEvent) UnmarshalJSON(data []byte) error { // but the requested transformation could not be generated. type UploadPostTransformErrorEvent struct { // Timestamp of when the event occurred in ISO8601 format. - CreatedAt time.Time `json:"created_at,required" format:"date-time"` - Data UploadPostTransformErrorEventData `json:"data,required"` - Request UploadPostTransformErrorEventRequest `json:"request,required"` - Type constant.UploadPostTransformError `json:"type,required"` + CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"` + Data UploadPostTransformErrorEventData `json:"data" api:"required"` + Request UploadPostTransformErrorEventRequest `json:"request" api:"required"` + Type constant.UploadPostTransformError `json:"type" default:"upload.post-transform.error"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { CreatedAt respjson.Field @@ -121,14 +121,14 @@ func (r *UploadPostTransformErrorEvent) UnmarshalJSON(data []byte) error { type UploadPostTransformErrorEventData struct { // Unique identifier of the originally uploaded file. - FileID string `json:"fileId,required"` + FileID string `json:"fileId" api:"required"` // Name of the file. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // Path of the file. - Path string `json:"path,required"` - Transformation UploadPostTransformErrorEventDataTransformation `json:"transformation,required"` + Path string `json:"path" api:"required"` + Transformation UploadPostTransformErrorEventDataTransformation `json:"transformation" api:"required"` // URL of the attempted post-transformation. - URL string `json:"url,required" format:"uri"` + URL string `json:"url" api:"required" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { FileID respjson.Field @@ -148,7 +148,7 @@ func (r *UploadPostTransformErrorEventData) UnmarshalJSON(data []byte) error { } type UploadPostTransformErrorEventDataTransformation struct { - Error UploadPostTransformErrorEventDataTransformationError `json:"error,required"` + Error UploadPostTransformErrorEventDataTransformationError `json:"error" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Error respjson.Field @@ -165,7 +165,7 @@ func (r *UploadPostTransformErrorEventDataTransformation) UnmarshalJSON(data []b type UploadPostTransformErrorEventDataTransformationError struct { // Reason for the post-transformation failure. - Reason string `json:"reason,required"` + Reason string `json:"reason" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Reason respjson.Field @@ -181,9 +181,9 @@ func (r *UploadPostTransformErrorEventDataTransformationError) UnmarshalJSON(dat } type UploadPostTransformErrorEventRequest struct { - Transformation UploadPostTransformErrorEventRequestTransformation `json:"transformation,required"` + Transformation UploadPostTransformErrorEventRequestTransformation `json:"transformation" api:"required"` // Unique identifier for the originating request. - XRequestID string `json:"x_request_id,required"` + XRequestID string `json:"x_request_id" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Transformation respjson.Field @@ -203,7 +203,7 @@ type UploadPostTransformErrorEventRequestTransformation struct { // Type of the requested post-transformation. // // Any of "transformation", "abs", "gif-to-video", "thumbnail". - Type string `json:"type,required"` + Type string `json:"type" api:"required"` // Only applicable if transformation type is 'abs'. Streaming protocol used. // // Any of "hls", "dash". @@ -231,10 +231,10 @@ func (r *UploadPostTransformErrorEventRequestTransformation) UnmarshalJSON(data // that each post-transformation generates a separate webhook event. type UploadPostTransformSuccessEvent struct { // Timestamp of when the event occurred in ISO8601 format. - CreatedAt time.Time `json:"created_at,required" format:"date-time"` - Data UploadPostTransformSuccessEventData `json:"data,required"` - Request UploadPostTransformSuccessEventRequest `json:"request,required"` - Type constant.UploadPostTransformSuccess `json:"type,required"` + CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"` + Data UploadPostTransformSuccessEventData `json:"data" api:"required"` + Request UploadPostTransformSuccessEventRequest `json:"request" api:"required"` + Type constant.UploadPostTransformSuccess `json:"type" default:"upload.post-transform.success"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { CreatedAt respjson.Field @@ -255,11 +255,11 @@ func (r *UploadPostTransformSuccessEvent) UnmarshalJSON(data []byte) error { type UploadPostTransformSuccessEventData struct { // Unique identifier of the originally uploaded file. - FileID string `json:"fileId,required"` + FileID string `json:"fileId" api:"required"` // Name of the file. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // URL of the generated post-transformation. - URL string `json:"url,required" format:"uri"` + URL string `json:"url" api:"required" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { FileID respjson.Field @@ -277,9 +277,9 @@ func (r *UploadPostTransformSuccessEventData) UnmarshalJSON(data []byte) error { } type UploadPostTransformSuccessEventRequest struct { - Transformation UploadPostTransformSuccessEventRequestTransformation `json:"transformation,required"` + Transformation UploadPostTransformSuccessEventRequestTransformation `json:"transformation" api:"required"` // Unique identifier for the originating request. - XRequestID string `json:"x_request_id,required"` + XRequestID string `json:"x_request_id" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Transformation respjson.Field @@ -299,7 +299,7 @@ type UploadPostTransformSuccessEventRequestTransformation struct { // Type of the requested post-transformation. // // Any of "transformation", "abs", "gif-to-video", "thumbnail". - Type string `json:"type,required"` + Type string `json:"type" api:"required"` // Only applicable if transformation type is 'abs'. Streaming protocol used. // // Any of "hls", "dash". @@ -326,10 +326,10 @@ func (r *UploadPostTransformSuccessEventRequestTransformation) UnmarshalJSON(dat // accepted, but the requested transformation could not be applied. type UploadPreTransformErrorEvent struct { // Timestamp of when the event occurred in ISO8601 format. - CreatedAt time.Time `json:"created_at,required" format:"date-time"` - Data UploadPreTransformErrorEventData `json:"data,required"` - Request UploadPreTransformErrorEventRequest `json:"request,required"` - Type constant.UploadPreTransformError `json:"type,required"` + CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"` + Data UploadPreTransformErrorEventData `json:"data" api:"required"` + Request UploadPreTransformErrorEventRequest `json:"request" api:"required"` + Type constant.UploadPreTransformError `json:"type" default:"upload.pre-transform.error"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { CreatedAt respjson.Field @@ -350,10 +350,10 @@ func (r *UploadPreTransformErrorEvent) UnmarshalJSON(data []byte) error { type UploadPreTransformErrorEventData struct { // Name of the file. - Name string `json:"name,required"` + Name string `json:"name" api:"required"` // Path of the file. - Path string `json:"path,required"` - Transformation UploadPreTransformErrorEventDataTransformation `json:"transformation,required"` + Path string `json:"path" api:"required"` + Transformation UploadPreTransformErrorEventDataTransformation `json:"transformation" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Name respjson.Field @@ -371,7 +371,7 @@ func (r *UploadPreTransformErrorEventData) UnmarshalJSON(data []byte) error { } type UploadPreTransformErrorEventDataTransformation struct { - Error UploadPreTransformErrorEventDataTransformationError `json:"error,required"` + Error UploadPreTransformErrorEventDataTransformationError `json:"error" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Error respjson.Field @@ -388,7 +388,7 @@ func (r *UploadPreTransformErrorEventDataTransformation) UnmarshalJSON(data []by type UploadPreTransformErrorEventDataTransformationError struct { // Reason for the pre-transformation failure. - Reason string `json:"reason,required"` + Reason string `json:"reason" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Reason respjson.Field @@ -405,9 +405,9 @@ func (r *UploadPreTransformErrorEventDataTransformationError) UnmarshalJSON(data type UploadPreTransformErrorEventRequest struct { // The requested pre-transformation string. - Transformation string `json:"transformation,required"` + Transformation string `json:"transformation" api:"required"` // Unique identifier for the originating request. - XRequestID string `json:"x_request_id,required"` + XRequestID string `json:"x_request_id" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Transformation respjson.Field @@ -428,11 +428,11 @@ func (r *UploadPreTransformErrorEventRequest) UnmarshalJSON(data []byte) error { // Library. type UploadPreTransformSuccessEvent struct { // Timestamp of when the event occurred in ISO8601 format. - CreatedAt time.Time `json:"created_at,required" format:"date-time"` + CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"` // Object containing details of a successful upload. - Data UploadPreTransformSuccessEventData `json:"data,required"` - Request UploadPreTransformSuccessEventRequest `json:"request,required"` - Type constant.UploadPreTransformSuccess `json:"type,required"` + Data UploadPreTransformSuccessEventData `json:"data" api:"required"` + Request UploadPreTransformSuccessEventRequest `json:"request" api:"required"` + Type constant.UploadPreTransformSuccess `json:"type" default:"upload.pre-transform.success"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { CreatedAt respjson.Field @@ -454,7 +454,7 @@ func (r *UploadPreTransformSuccessEvent) UnmarshalJSON(data []byte) error { // Object containing details of a successful upload. type UploadPreTransformSuccessEventData struct { // An array of tags assigned to the uploaded file by auto tagging. - AITags []UploadPreTransformSuccessEventDataAITag `json:"AITags,nullable"` + AITags []UploadPreTransformSuccessEventDataAITag `json:"AITags" api:"nullable"` // The audio codec used in the video (only for video). AudioCodec string `json:"audioCodec"` // The bit rate of the video in kbps (only for video). @@ -463,7 +463,7 @@ type UploadPreTransformSuccessEventData struct { // `x,y,width,height`. If `customCoordinates` are not defined, then it is `null`. // Send `customCoordinates` in `responseFields` in API request to get the value of // this field. - CustomCoordinates string `json:"customCoordinates,nullable"` + CustomCoordinates string `json:"customCoordinates" api:"nullable"` // A key-value data associated with the asset. Use `responseField` in API request // to get `customMetadata` in the upload API response. Before setting any custom // metadata on an asset, you have to create the field using custom metadata fields @@ -525,7 +525,7 @@ type UploadPreTransformSuccessEventData struct { // The array of tags associated with the asset. If no tags are set, it will be // `null`. Send `tags` in `responseFields` in API request to get the value of this // field. - Tags []string `json:"tags,nullable"` + Tags []string `json:"tags" api:"nullable"` // In the case of an image, a small thumbnail URL. ThumbnailURL string `json:"thumbnailUrl"` // A publicly accessible URL of the file. @@ -642,7 +642,7 @@ type UploadPreTransformSuccessEventDataSelectedFieldsSchema struct { // // Any of "Text", "Textarea", "Number", "Date", "Boolean", "SingleSelect", // "MultiSelect". - Type string `json:"type,required"` + Type string `json:"type" api:"required"` // The default value for this custom metadata field. The value should match the // `type` of custom metadata field. DefaultValue UploadPreTransformSuccessEventDataSelectedFieldsSchemaDefaultValueUnion `json:"defaultValue"` @@ -940,9 +940,9 @@ func (r *UploadPreTransformSuccessEventDataVersionInfo) UnmarshalJSON(data []byt type UploadPreTransformSuccessEventRequest struct { // The requested pre-transformation string. - Transformation string `json:"transformation,required"` + Transformation string `json:"transformation" api:"required"` // Unique identifier for the originating request. - XRequestID string `json:"x_request_id,required"` + XRequestID string `json:"x_request_id" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Transformation respjson.Field @@ -963,11 +963,11 @@ func (r *UploadPreTransformSuccessEventRequest) UnmarshalJSON(data []byte) error // request. Use this for debugging and tracking transformation lifecycle. type VideoTransformationAcceptedEvent struct { // Timestamp when the event was created in ISO8601 format. - CreatedAt time.Time `json:"created_at,required" format:"date-time"` - Data VideoTransformationAcceptedEventData `json:"data,required"` + CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"` + Data VideoTransformationAcceptedEventData `json:"data" api:"required"` // Information about the original request that triggered the video transformation. - Request VideoTransformationAcceptedEventRequest `json:"request,required"` - Type constant.VideoTransformationAccepted `json:"type,required"` + Request VideoTransformationAcceptedEventRequest `json:"request" api:"required"` + Type constant.VideoTransformationAccepted `json:"type" default:"video.transformation.accepted"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { CreatedAt respjson.Field @@ -988,9 +988,9 @@ func (r *VideoTransformationAcceptedEvent) UnmarshalJSON(data []byte) error { type VideoTransformationAcceptedEventData struct { // Information about the source video asset being transformed. - Asset VideoTransformationAcceptedEventDataAsset `json:"asset,required"` + Asset VideoTransformationAcceptedEventDataAsset `json:"asset" api:"required"` // Base information about a video transformation request. - Transformation VideoTransformationAcceptedEventDataTransformation `json:"transformation,required"` + Transformation VideoTransformationAcceptedEventDataTransformation `json:"transformation" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Asset respjson.Field @@ -1009,7 +1009,7 @@ func (r *VideoTransformationAcceptedEventData) UnmarshalJSON(data []byte) error // Information about the source video asset being transformed. type VideoTransformationAcceptedEventDataAsset struct { // URL to download or access the source video file. - URL string `json:"url,required" format:"uri"` + URL string `json:"url" api:"required" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { URL respjson.Field @@ -1034,7 +1034,7 @@ type VideoTransformationAcceptedEventDataTransformation struct { // - `video-thumbnail`: Generate thumbnail image from video // // Any of "video-transformation", "gif-to-video", "video-thumbnail". - Type string `json:"type,required"` + Type string `json:"type" api:"required"` // Configuration options for video transformations. Options VideoTransformationAcceptedEventDataTransformationOptions `json:"options"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -1101,9 +1101,9 @@ func (r *VideoTransformationAcceptedEventDataTransformationOptions) UnmarshalJSO // Information about the original request that triggered the video transformation. type VideoTransformationAcceptedEventRequest struct { // Full URL of the transformation request that was submitted. - URL string `json:"url,required" format:"uri"` + URL string `json:"url" api:"required" format:"uri"` // Unique identifier for the originating transformation request. - XRequestID string `json:"x_request_id,required"` + XRequestID string `json:"x_request_id" api:"required"` // User-Agent header from the original request that triggered the transformation. UserAgent string `json:"user_agent"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -1128,11 +1128,11 @@ func (r *VideoTransformationAcceptedEventRequest) UnmarshalJSON(data []byte) err // support. type VideoTransformationErrorEvent struct { // Timestamp when the event was created in ISO8601 format. - CreatedAt time.Time `json:"created_at,required" format:"date-time"` - Data VideoTransformationErrorEventData `json:"data,required"` + CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"` + Data VideoTransformationErrorEventData `json:"data" api:"required"` // Information about the original request that triggered the video transformation. - Request VideoTransformationErrorEventRequest `json:"request,required"` - Type constant.VideoTransformationError `json:"type,required"` + Request VideoTransformationErrorEventRequest `json:"request" api:"required"` + Type constant.VideoTransformationError `json:"type" default:"video.transformation.error"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { CreatedAt respjson.Field @@ -1153,8 +1153,8 @@ func (r *VideoTransformationErrorEvent) UnmarshalJSON(data []byte) error { type VideoTransformationErrorEventData struct { // Information about the source video asset being transformed. - Asset VideoTransformationErrorEventDataAsset `json:"asset,required"` - Transformation VideoTransformationErrorEventDataTransformation `json:"transformation,required"` + Asset VideoTransformationErrorEventDataAsset `json:"asset" api:"required"` + Transformation VideoTransformationErrorEventDataTransformation `json:"transformation" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Asset respjson.Field @@ -1173,7 +1173,7 @@ func (r *VideoTransformationErrorEventData) UnmarshalJSON(data []byte) error { // Information about the source video asset being transformed. type VideoTransformationErrorEventDataAsset struct { // URL to download or access the source video file. - URL string `json:"url,required" format:"uri"` + URL string `json:"url" api:"required" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { URL respjson.Field @@ -1197,7 +1197,7 @@ type VideoTransformationErrorEventDataTransformation struct { // - `video-thumbnail`: Generate thumbnail image from video // // Any of "video-transformation", "gif-to-video", "video-thumbnail". - Type string `json:"type,required"` + Type string `json:"type" api:"required"` // Details about the transformation error. Error VideoTransformationErrorEventDataTransformationError `json:"error"` // Configuration options for video transformations. @@ -1227,7 +1227,7 @@ type VideoTransformationErrorEventDataTransformationError struct { // - `internal_server_error`: Unexpected server error // // Any of "encoding_failed", "download_failed", "internal_server_error". - Reason string `json:"reason,required"` + Reason string `json:"reason" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Reason respjson.Field @@ -1289,9 +1289,9 @@ func (r *VideoTransformationErrorEventDataTransformationOptions) UnmarshalJSON(d // Information about the original request that triggered the video transformation. type VideoTransformationErrorEventRequest struct { // Full URL of the transformation request that was submitted. - URL string `json:"url,required" format:"uri"` + URL string `json:"url" api:"required" format:"uri"` // Unique identifier for the originating transformation request. - XRequestID string `json:"x_request_id,required"` + XRequestID string `json:"x_request_id" api:"required"` // User-Agent header from the original request that triggered the transformation. UserAgent string `json:"user_agent"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -1316,11 +1316,11 @@ func (r *VideoTransformationErrorEventRequest) UnmarshalJSON(data []byte) error // transformed video to users. type VideoTransformationReadyEvent struct { // Timestamp when the event was created in ISO8601 format. - CreatedAt time.Time `json:"created_at,required" format:"date-time"` - Data VideoTransformationReadyEventData `json:"data,required"` + CreatedAt time.Time `json:"created_at" api:"required" format:"date-time"` + Data VideoTransformationReadyEventData `json:"data" api:"required"` // Information about the original request that triggered the video transformation. - Request VideoTransformationReadyEventRequest `json:"request,required"` - Type constant.VideoTransformationReady `json:"type,required"` + Request VideoTransformationReadyEventRequest `json:"request" api:"required"` + Type constant.VideoTransformationReady `json:"type" default:"video.transformation.ready"` // Performance metrics for the transformation process. Timings VideoTransformationReadyEventTimings `json:"timings"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -1344,8 +1344,8 @@ func (r *VideoTransformationReadyEvent) UnmarshalJSON(data []byte) error { type VideoTransformationReadyEventData struct { // Information about the source video asset being transformed. - Asset VideoTransformationReadyEventDataAsset `json:"asset,required"` - Transformation VideoTransformationReadyEventDataTransformation `json:"transformation,required"` + Asset VideoTransformationReadyEventDataAsset `json:"asset" api:"required"` + Transformation VideoTransformationReadyEventDataTransformation `json:"transformation" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Asset respjson.Field @@ -1364,7 +1364,7 @@ func (r *VideoTransformationReadyEventData) UnmarshalJSON(data []byte) error { // Information about the source video asset being transformed. type VideoTransformationReadyEventDataAsset struct { // URL to download or access the source video file. - URL string `json:"url,required" format:"uri"` + URL string `json:"url" api:"required" format:"uri"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { URL respjson.Field @@ -1388,7 +1388,7 @@ type VideoTransformationReadyEventDataTransformation struct { // - `video-thumbnail`: Generate thumbnail image from video // // Any of "video-transformation", "gif-to-video", "video-thumbnail". - Type string `json:"type,required"` + Type string `json:"type" api:"required"` // Configuration options for video transformations. Options VideoTransformationReadyEventDataTransformationOptions `json:"options"` // Information about the transformed output video. @@ -1456,7 +1456,7 @@ func (r *VideoTransformationReadyEventDataTransformationOptions) UnmarshalJSON(d // Information about the transformed output video. type VideoTransformationReadyEventDataTransformationOutput struct { // URL to access the transformed video. - URL string `json:"url,required" format:"uri"` + URL string `json:"url" api:"required" format:"uri"` // Metadata of the output video file. VideoMetadata VideoTransformationReadyEventDataTransformationOutputVideoMetadata `json:"video_metadata"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. @@ -1477,13 +1477,13 @@ func (r *VideoTransformationReadyEventDataTransformationOutput) UnmarshalJSON(da // Metadata of the output video file. type VideoTransformationReadyEventDataTransformationOutputVideoMetadata struct { // Bitrate of the output video in bits per second. - Bitrate int64 `json:"bitrate,required"` + Bitrate int64 `json:"bitrate" api:"required"` // Duration of the output video in seconds. - Duration float64 `json:"duration,required"` + Duration float64 `json:"duration" api:"required"` // Height of the output video in pixels. - Height int64 `json:"height,required"` + Height int64 `json:"height" api:"required"` // Width of the output video in pixels. - Width int64 `json:"width,required"` + Width int64 `json:"width" api:"required"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. JSON struct { Bitrate respjson.Field @@ -1506,9 +1506,9 @@ func (r *VideoTransformationReadyEventDataTransformationOutputVideoMetadata) Unm // Information about the original request that triggered the video transformation. type VideoTransformationReadyEventRequest struct { // Full URL of the transformation request that was submitted. - URL string `json:"url,required" format:"uri"` + URL string `json:"url" api:"required" format:"uri"` // Unique identifier for the originating transformation request. - XRequestID string `json:"x_request_id,required"` + XRequestID string `json:"x_request_id" api:"required"` // User-Agent header from the original request that triggered the transformation. UserAgent string `json:"user_agent"` // JSON contains metadata for fields, check presence with [respjson.Field.Valid]. diff --git a/webhook_test.go b/webhook_test.go index 23f90c8..2e2195a 100644 --- a/webhook_test.go +++ b/webhook_test.go @@ -22,13 +22,13 @@ func TestWebhookUnwrap(t *testing.T) { payload := []byte(`{"id":"id","type":"video.transformation.accepted","created_at":"2019-12-27T18:11:19.117Z","data":{"asset":{"url":"https://example.com"},"transformation":{"type":"video-transformation","options":{"audio_codec":"aac","auto_rotate":true,"format":"mp4","quality":0,"stream_protocol":"HLS","variants":["string"],"video_codec":"h264"}}},"request":{"url":"https://example.com","x_request_id":"x_request_id","user_agent":"user_agent"}}`) wh, err := standardwebhooks.NewWebhook("whsec_c2VjcmV0Cg==") if err != nil { - t.Error("Failed to sign test webhook message") + t.Fatal("Failed to sign test webhook message", err) } msgID := "1" now := time.Now() sig, err := wh.Sign(msgID, now, payload) if err != nil { - t.Error("Failed to sign test webhook message:", err) + t.Fatal("Failed to sign test webhook message:", err) } headers := make(http.Header) headers.Set("webhook-signature", sig) @@ -36,6 +36,6 @@ func TestWebhookUnwrap(t *testing.T) { headers.Set("webhook-timestamp", strconv.FormatInt(now.Unix(), 10)) _, err = client.Webhooks.Unwrap(payload, headers) if err != nil { - t.Error("Failed to unwrap webhook:", err) + t.Fatal("Failed to unwrap webhook:", err) } }