diff --git a/.gitignore b/.gitignore index 3f5f2c5..3d26cee 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,3 @@ bin/tapioca Brewfile.lock.json doc/ sorbet/tapioca/* -examples/temp* \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index f2cb4f6..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "recommendations": [ - "shopify.ruby-lsp", - "sorbet.sorbet-vscode-extension", - "soutaro.rbs-syntax", - "bradlc.vscode-tailwindcss", - "github.copilot", - "github.copilot-chat" - ], - "unwantedRecommendations": [ - "rebornix.ruby", - "castwide.solargraph" - ] -} diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index f52f0ae..0000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "ruby.interpreter": "ruby", - "ruby.pathToBundler": "bundle", - "ruby.useLanguageServer": true, - "ruby.lint": { - "rubocop": true, - "ruby": true - }, - "ruby.format": "rubocop", - "sorbet.enabled": true, - "sorbet.typeCheckingMode": "strict", - "sorbet.watchmanPath": "watchman", - "files.associations": { - "*.rb": "ruby", - "*.rbi": "ruby", - "*.rbs": "rbs", - "Gemfile": "ruby", - "Rakefile": "ruby" - }, - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.fixAll.rubocop": "explicit" - }, - "[ruby]": { - "editor.defaultFormatter": "Shopify.ruby-lsp", - "editor.formatOnSave": true, - "editor.tabSize": 2, - "editor.insertSpaces": true, - "editor.semanticHighlighting.enabled": true, - "editor.suggest.insertMode": "replace" - }, - "[rbs]": { - "editor.defaultFormatter": "soutaro.rbs-syntax", - "editor.tabSize": 2, - "editor.insertSpaces": true - } -} diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index b37e93d..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,185 +0,0 @@ -# Changelog - -## 4.2.0 (2026-02-02) - -Full Changelog: [v4.1.2...v4.2.0](https://github.com/imagekit-developer/imagekit-ruby/compare/v4.1.2...v4.2.0) - -### Features - -* **api:** add customMetadata property to folder schema ([8038b9e](https://github.com/imagekit-developer/imagekit-ruby/commit/8038b9ecc161c7d25c65a35c2d54149ace184479)) - - -### Bug Fixes - -* **api:** add missing embeddedMetadata and video properties to FileDetails ([898add4](https://github.com/imagekit-developer/imagekit-ruby/commit/898add425e5839e85fc8cca8bd8035923ec39463)) - -## 4.1.2 (2026-01-29) - -Full Changelog: [v4.1.1...v4.1.2](https://github.com/imagekit-developer/imagekit-ruby/compare/v4.1.1...v4.1.2) - -### Bug Fixes - -* **docs:** fix mcp installation instructions for remote servers ([84672e6](https://github.com/imagekit-developer/imagekit-ruby/commit/84672e63bc4b4621e1c35ce3d1a9029566b0e1e7)) -* update overlay parameter from 'l-subtitle' to 'l-subtitles' in URL generation ([2acbe47](https://github.com/imagekit-developer/imagekit-ruby/commit/2acbe47f75d0235bd8bfc6213acac361e0b3a07e)) - -## 4.1.1 (2026-01-20) - -Full Changelog: [v4.1.0...v4.1.1](https://github.com/imagekit-developer/imagekit-ruby/compare/v4.1.0...v4.1.1) - -### Bug Fixes - -* vocab field is required ([1ebdd2d](https://github.com/imagekit-developer/imagekit-ruby/commit/1ebdd2dff81b620d7d7dd7dea842424790b503f4)) - - -### Chores - -* **internal:** update `actions/checkout` version ([1e2d69e](https://github.com/imagekit-developer/imagekit-ruby/commit/1e2d69e80f0550dc26aea92609f1a355f5335270)) - -## 4.1.0 (2026-01-16) - -Full Changelog: [v4.0.0...v4.1.0](https://github.com/imagekit-developer/imagekit-ruby/compare/v4.0.0...v4.1.0) - -### Features - -* add layer_mode property to overlays and new transformation options ([97042ce](https://github.com/imagekit-developer/imagekit-ruby/commit/97042ce9bffaf101ab98dd7394caaf4df9a873ea)) -* **api:** Add saved extensions API and enhance transformation options ([f1dc75e](https://github.com/imagekit-developer/imagekit-ruby/commit/f1dc75ecbe0a4a39472fdc10e9dc8f02e75ddc07)) - - -### Bug Fixes - -* add ai-tasks property to response schemas with enum values ([aad5e54](https://github.com/imagekit-developer/imagekit-ruby/commit/aad5e5413676af916e8149f07ae78aaff7c5c313)) -* better thread safety via early initializing SSL store during HTTP client creation ([2bc0835](https://github.com/imagekit-developer/imagekit-ruby/commit/2bc0835981c29b717f0ad3a7d78c3c78027874e0)) -* calling `break` out of streams should be instantaneous ([55bf4a9](https://github.com/imagekit-developer/imagekit-ruby/commit/55bf4a9b768f18f4adad903b2c9d93178a670151)) -* issue where json.parse errors when receiving HTTP 204 with nobody ([dd32cb1](https://github.com/imagekit-developer/imagekit-ruby/commit/dd32cb1572bc155db85ed898011374889996b3fd)) -* remove redundant base64 require statement ([4c73b42](https://github.com/imagekit-developer/imagekit-ruby/commit/4c73b425564e980b21dfd1f3554f8a2e45aaeecf)) - - -### Chores - -* bump dependency version and update sorbet types ([8d89fb2](https://github.com/imagekit-developer/imagekit-ruby/commit/8d89fb2c1654420f83bb7efedcc9056c5a7e3c79)) -* **client:** send user-agent header ([796027d](https://github.com/imagekit-developer/imagekit-ruby/commit/796027d185c93067c32bac98323d8a82aeaf9bfe)) -* explicitly require "base64" gem ([1b4181d](https://github.com/imagekit-developer/imagekit-ruby/commit/1b4181d4e57d2c12306f6d3f43b832f63ab68053)) -* **internal:** codegen related update ([3a93def](https://github.com/imagekit-developer/imagekit-ruby/commit/3a93def2d09609b359824a627183833ae59d74e1)) -* **internal:** codegen related update ([4c161f0](https://github.com/imagekit-developer/imagekit-ruby/commit/4c161f048927df137a12d33a5a1b79af1c561b8b)) -* move `cgi` into dependencies for ruby 4 ([54261ef](https://github.com/imagekit-developer/imagekit-ruby/commit/54261ef9f24e206d2180dc0a205464154af4c3ed)) - - -### Documentation - -* prominently feature MCP server setup in root SDK readmes ([777f8cf](https://github.com/imagekit-developer/imagekit-ruby/commit/777f8cf5cc692eed3e8f6217caf25a85d17201f7)) -* remove MCP Server section from README ([db0f71c](https://github.com/imagekit-developer/imagekit-ruby/commit/db0f71cce159f4c395fe8c7c0526d4108934fc6b)) - -## 4.0.0 (2025-11-03) - -Full Changelog: [v0.0.1...v4.0.0](https://github.com/imagekit-developer/imagekit-ruby/compare/v0.0.1...v4.0.0) - -### Features - -* add get_responsive_image_attributes method with options parameter ([766ded9](https://github.com/imagekit-developer/imagekit-ruby/commit/766ded9f6644cdc0f4638980ca78b51a877fe309)) -* add responsive image attributes generation for HTML <img> tags ([13edc3d](https://github.com/imagekit-developer/imagekit-ruby/commit/13edc3d82f92d19869f672bd955a9045a13e0a16)) -* **api:** add BaseWebhookEvent ([b4c2a83](https://github.com/imagekit-developer/imagekit-ruby/commit/b4c2a8398c1b8bfa1df7da222ede418b047fe0b1)) -* **api:** add GetImageAttributesOptions and ResponsiveImageAttributes schemas; update resource references in main.yaml; remove dummy endpoint ([08560d4](https://github.com/imagekit-developer/imagekit-ruby/commit/08560d45c6390460f14c8b76ce42292ed3303047)) -* **api:** add path policy related non-breaking changes ([b24e025](https://github.com/imagekit-developer/imagekit-ruby/commit/b24e025ed565cd1a0f3906838c24d1fc5588f3fd)) -* **api:** add selectedFieldsSchema in upload and list API response ([557f058](https://github.com/imagekit-developer/imagekit-ruby/commit/557f0588a6352568ca0b7be28fe1759717c59aa5)) -* **api:** extract UpdateFileDetailsRequest to model ([9aaa659](https://github.com/imagekit-developer/imagekit-ruby/commit/9aaa6599d67f4d077d34d0afec3c08baef271b9b)) -* **api:** fix go sdk breaking changes ([525a5aa](https://github.com/imagekit-developer/imagekit-ruby/commit/525a5aa25dba80a109fc5d53535cf2f8fa2250dd)) -* **api:** fix upload API request params ([0ac922a](https://github.com/imagekit-developer/imagekit-ruby/commit/0ac922a79db6de564a0ec9dc5405a5171c1d7109)) -* **api:** manual updates ([eaa294e](https://github.com/imagekit-developer/imagekit-ruby/commit/eaa294e74f32dea948ceaec8a5e44223075dabf8)) -* **api:** manual updates ([9604a8e](https://github.com/imagekit-developer/imagekit-ruby/commit/9604a8eb40f6e4947075d6ff80bf919062a1556f)) -* **api:** manual updates ([0682128](https://github.com/imagekit-developer/imagekit-ruby/commit/0682128a78d935ba01979783050d66aac099504a)) -* **api:** manual updates ([f9bee87](https://github.com/imagekit-developer/imagekit-ruby/commit/f9bee8789b20c3ae42a177e8e7adc086fd6b734a)) -* **api:** manual updates ([2f5a40a](https://github.com/imagekit-developer/imagekit-ruby/commit/2f5a40ab9e7c3ffc0755c8c8cbf26bcfe69ab5b0)) -* **api:** manual updates ([428829b](https://github.com/imagekit-developer/imagekit-ruby/commit/428829bb7d7a3e01621dcb6d9901a1b440481f7c)) -* **api:** manual updates ([54e5bdf](https://github.com/imagekit-developer/imagekit-ruby/commit/54e5bdf49a3a67eb494e7aecfd4f5300f8c07772)) -* **api:** manual updates ([8c970ed](https://github.com/imagekit-developer/imagekit-ruby/commit/8c970ed1b42cfb40e05cedf4f643096918097f67)) -* **api:** manual updates ([e33d6ed](https://github.com/imagekit-developer/imagekit-ruby/commit/e33d6ed379d8d298f049edcf5b5b4d2ecfdd82bd)) -* **api:** manual updates ([4c04de9](https://github.com/imagekit-developer/imagekit-ruby/commit/4c04de93766bb15aad1784f5a4a594036fdce827)) -* **api:** manual updates ([e9bad22](https://github.com/imagekit-developer/imagekit-ruby/commit/e9bad2213d947539b07f4c71622c6bee2e826274)) -* **api:** manual updates ([c0417fb](https://github.com/imagekit-developer/imagekit-ruby/commit/c0417fbd4286fb47cbdfc154a696fcd2d34b1b5d)) -* **api:** manual updates ([bddb2fa](https://github.com/imagekit-developer/imagekit-ruby/commit/bddb2faecc78b22888d44aeda6896bdeff0f7cf8)) -* **api:** manual updates ([24f9f11](https://github.com/imagekit-developer/imagekit-ruby/commit/24f9f11ca39e3611c621a1d5383d763a4acd87b4)) -* **api:** manual updates ([8ac0ad3](https://github.com/imagekit-developer/imagekit-ruby/commit/8ac0ad3ff00d4036d52ec31777d74cb19f8d4379)) -* **api:** manual updates ([c64d558](https://github.com/imagekit-developer/imagekit-ruby/commit/c64d558fc172b4c1768d59731dc2a0e2c71de2fb)) -* **api:** manual updates ([453e942](https://github.com/imagekit-developer/imagekit-ruby/commit/453e942ec2c25f3720305dcd564ca22b85815336)) -* **api:** modify upload options serialization for backend API compatibility ([2d9cda5](https://github.com/imagekit-developer/imagekit-ruby/commit/2d9cda5fd408c5359f455c989585a8a8e3528676)) -* **api:** remove Stainless attribution from readme ([45e7793](https://github.com/imagekit-developer/imagekit-ruby/commit/45e7793eae012f4fcd05a30aa1ff4ef695793792)) -* **api:** update api docs link ([03ecbdf](https://github.com/imagekit-developer/imagekit-ruby/commit/03ecbdffb5dddc16aeace01e5b86a7e525263d7b)) -* **api:** Update env var name ([db61f60](https://github.com/imagekit-developer/imagekit-ruby/commit/db61f6089520c631dccbc618453d018634e53e63)) -* **api:** update gem name ([a966137](https://github.com/imagekit-developer/imagekit-ruby/commit/a966137abb937faa25451baafcd41e32c0d16b7e)) -* **api:** updated docs ([c2d983e](https://github.com/imagekit-developer/imagekit-ruby/commit/c2d983ed07adab3c0031f18174b0dcf95a5ba26d)) -* expose response headers for both streams and errors ([72c02c3](https://github.com/imagekit-developer/imagekit-ruby/commit/72c02c37a42bddc4e191b43145a562fab9e01dc7)) -* handle thread interrupts in the core HTTP client ([4d258e9](https://github.com/imagekit-developer/imagekit-ruby/commit/4d258e9d5fc3cb2d2e74e26d605e87b7852736a4)) -* pass all test cases ([1cfd9cb](https://github.com/imagekit-developer/imagekit-ruby/commit/1cfd9cb2229352e8d2ba4a005fc214fbfd73c1ba)) -* **tests:** add support for plain hashes in various helper methods and tests ([f7a8f2d](https://github.com/imagekit-developer/imagekit-ruby/commit/f7a8f2d0cdb258abbc04d73eb7458d371948f2d8)) -* **tests:** add test for generating signed URLs in responsive image attributes ([41b17ab](https://github.com/imagekit-developer/imagekit-ruby/commit/41b17abff1fdd1dc63e7b5cb1b3eff765f8955f4)) -* **tests:** add tests to ensure integer descriptors in srcset for responsive image attributes ([fab9156](https://github.com/imagekit-developer/imagekit-ruby/commit/fab915681615569c608439025992325210391e61)) - - -### Bug Fixes - -* absolutely qualified uris should always override the default ([eebaf5e](https://github.com/imagekit-developer/imagekit-ruby/commit/eebaf5ef3d7b60eb051d4e1a146dee8e0eae66ec)) -* add examples/temp* to .gitignore ([2e76262](https://github.com/imagekit-developer/imagekit-ruby/commit/2e762620a6e8179d3f873306596ea623bd6e539d)) -* always send `filename=...` for multipart requests where a file is expected ([9cf2e92](https://github.com/imagekit-developer/imagekit-ruby/commit/9cf2e92f6bd271a6ffa538176d836786f9ae72bc)) -* carrierwave bump to rm mimemagic dep ([ab4c2cf](https://github.com/imagekit-developer/imagekit-ruby/commit/ab4c2cf5856de50a9cb9deb7fb2168d67258083d)) -* change to dev dep ([22b98f8](https://github.com/imagekit-developer/imagekit-ruby/commit/22b98f8a9f482f11c0e6c3cfe9650a75e62d7f17)) -* coroutine leaks from connection pool ([62e54e5](https://github.com/imagekit-developer/imagekit-ruby/commit/62e54e54eaa2201beeedbacd41452e7eb7d6b1d7)) -* **deps:** update gem dependencies to latest versions in Gemfile.lock ([0cfea18](https://github.com/imagekit-developer/imagekit-ruby/commit/0cfea1897d6c71f8a24bf4795b46553d5d937693)) -* **docs:** enhance README to clarify features and integration with Ruby on Rails ([22c2cec](https://github.com/imagekit-developer/imagekit-ruby/commit/22c2cec88e2c6a37f10dce061eb555e70fe7715d)) -* **docs:** remove unnecessary Bundler setup requirement from usage example in README ([b3355da](https://github.com/imagekit-developer/imagekit-ruby/commit/b3355dad701bb557b5f93281330cc68b6b49011c)) -* **docs:** streamline documentation for Ruby on Rails integration and remove redundant sections ([855c7f9](https://github.com/imagekit-developer/imagekit-ruby/commit/855c7f95644f493d5d670a76c571b9c245493e73)) -* **docs:** update README examples for file uploads and remove obsolete parameters ([17a776a](https://github.com/imagekit-developer/imagekit-ruby/commit/17a776a445401889f0624bf05de2317408f9c1e1)) -* **docs:** update README examples to use File.read instead of StringIO for file uploads ([ca62b83](https://github.com/imagekit-developer/imagekit-ruby/commit/ca62b8326f92b584d805bbe22f133b46f3f84423)) -* **docs:** update README to enhance clarity on Ruby documentation and Rails integration ([e5f64f1](https://github.com/imagekit-developer/imagekit-ruby/commit/e5f64f1a20cb2fb02f23378636053bc0e1bf4957)) -* **docs:** update README to enhance documentation for Ruby on Rails integration and remove outdated sections ([d1760a3](https://github.com/imagekit-developer/imagekit-ruby/commit/d1760a31d0cde39067114c1d913d4c0d0ce8d1c1)) -* **docs:** update README to reflect gem name change from imagekit to imagekitio ([6beb35d](https://github.com/imagekit-developer/imagekit-ruby/commit/6beb35d38eb07ae157a000b953380f948a550c5f)) -* README.md linking sections ([9101ca2](https://github.com/imagekit-developer/imagekit-ruby/commit/9101ca2f3676a28d92c84c3b1b2c1c78ab5d027d)) -* shorten multipart boundary sep to less than RFC specificed max length ([b2ffa6a](https://github.com/imagekit-developer/imagekit-ruby/commit/b2ffa6a8b489b151c50f76f56ad79376aabbcbcb)) -* should not reuse buffers for `IO.copy_stream` interop ([80dcda6](https://github.com/imagekit-developer/imagekit-ruby/commit/80dcda667c50f379514018fbf9db84b1a624fc2e)) -* spelling typo ([8debe83](https://github.com/imagekit-developer/imagekit-ruby/commit/8debe8379dbebdc7aad334acd1d8ac69283b0f94)) -* standardize naming from "Image Kit" to "ImageKit" across documentation and gemspec ([c427415](https://github.com/imagekit-developer/imagekit-ruby/commit/c427415b3424b544bd0b61188d95b1fa90846a38)) -* update namespace for coerce_hash! method in file upload parameters ([f3e7216](https://github.com/imagekit-developer/imagekit-ruby/commit/f3e72163a0000d8f526ad67f1183c1d185772cf4)) - - -### Performance Improvements - -* faster code formatting ([8005df1](https://github.com/imagekit-developer/imagekit-ruby/commit/8005df172660b8610889bd2a478774c38b26cb7d)) - - -### Chores - -* allow fast-format to use bsd sed as well ([81093a0](https://github.com/imagekit-developer/imagekit-ruby/commit/81093a0420de0f10a331fb8d878cc2d9322ca1ec)) -* do not install brew dependencies in ./scripts/bootstrap by default ([14104e2](https://github.com/imagekit-developer/imagekit-ruby/commit/14104e2b691d586fe0e978a6c6e4232d2e6db650)) -* ignore linter error for tests having large collections ([86d5b43](https://github.com/imagekit-developer/imagekit-ruby/commit/86d5b4308f574b456e7f4fd8f094cf02fba39114)) -* **internal:** codegen related update ([d13a1d7](https://github.com/imagekit-developer/imagekit-ruby/commit/d13a1d73432f2ed5a54a7ad624cdc8237b15eb81)) -* remove example upload script ([efe2092](https://github.com/imagekit-developer/imagekit-ruby/commit/efe2092315ca68b4d9b7ede16ba4e624ec1f3adc)) -* sync repo ([0200fb8](https://github.com/imagekit-developer/imagekit-ruby/commit/0200fb885ff82f4960f401169d728b48c9d900cf)) -* update SDK settings ([15d893e](https://github.com/imagekit-developer/imagekit-ruby/commit/15d893e96bc5ae52e5e0cefe24818c248a047d3e)) -* update SDK settings ([5ce5d1f](https://github.com/imagekit-developer/imagekit-ruby/commit/5ce5d1f2370b6b31c1d2927856bfeac5eb592a23)) - - -### Documentation - -* correct typo in default value description for custom metadata field ([c16e257](https://github.com/imagekit-developer/imagekit-ruby/commit/c16e257b541f1fd5063f8feeac74ba7b214d0507)) -* update README to enhance URL generation section with detailed examples and new features ([f1687c0](https://github.com/imagekit-developer/imagekit-ruby/commit/f1687c0784b4633a3e55165f62f14ef7d8bbd5c8)) - - -### Refactors - -* consolidate handling of tags and responseFields for improved clarity ([2b7d54e](https://github.com/imagekit-developer/imagekit-ruby/commit/2b7d54e8592d36f8db8eaebffdae65aa4f1527e7)) -* format and fix all lint issues ([091e6d2](https://github.com/imagekit-developer/imagekit-ruby/commit/091e6d29618ee8337f4fe4ea6d82c77748520b65)) -* remove unnecessary require statements for improved clarity ([75820cd](https://github.com/imagekit-developer/imagekit-ruby/commit/75820cdc78cae2383c7e6061f359b1cc40a93d52)) -* rename generateTransformationString to buildTransformationString for consistency ([028871e](https://github.com/imagekit-developer/imagekit-ruby/commit/028871e9aa23e61b7ba1432874ed99943aec4c0f)) -* simplify overlay processing and enhance safe property access ([f35d7eb](https://github.com/imagekit-developer/imagekit-ruby/commit/f35d7eb50bd2eafd74f355d9a6edd992ae9b995c)) -* standardize method naming for URL and transformation string generation ([f736fef](https://github.com/imagekit-developer/imagekit-ruby/commit/f736fefcd85bf65204fce105969671608551ee89)) -* streamline model object handling and enhance safe property access ([ebf5887](https://github.com/imagekit-developer/imagekit-ruby/commit/ebf5887fb945ae99807327e2361263612a734c00)) -* **tests:** remove password parameter from client setup in URL generation tests ([3cf2616](https://github.com/imagekit-developer/imagekit-ruby/commit/3cf26166baf9369b3e32203c202b3d44f68d177b)) -* unify helper attribute naming across client and test files ([67d2ecb](https://github.com/imagekit-developer/imagekit-ruby/commit/67d2ecb8de8f2889c7473d2635a172b5346bcfde)) -* update method calls to use fully qualified names for clarity ([a45cc83](https://github.com/imagekit-developer/imagekit-ruby/commit/a45cc83d04301758db54a1cfa96364ddb7002959)) -* update parameter naming for build_url method to use options ([cd3618c](https://github.com/imagekit-developer/imagekit-ruby/commit/cd3618c5bb747640da0b255d46206bdd6ee0d300)) - - -### Build System - -* **deps:** bump addressable from 2.7.0 to 2.8.0 in /samples/rails_app ([db074cc](https://github.com/imagekit-developer/imagekit-ruby/commit/db074cc81e5aa59fa962b5e26c25d327bb4cac87)) -* **deps:** bump carrierwave from 2.1.0 to 2.1.1 in /samples/rails_app ([c109b9b](https://github.com/imagekit-developer/imagekit-ruby/commit/c109b9bd0effff643b8062dbe9d1157dad0210d8)) -* **deps:** bump nokogiri from 1.10.10 to 1.11.4 in /samples/rails_app ([9497849](https://github.com/imagekit-developer/imagekit-ruby/commit/9497849e1caa72bc5bbc582da3fc5f6575f2b455)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a225d78..021d116 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -43,13 +43,13 @@ If you’d like to use the repository from source, you can either install from g To install via git in your `Gemfile`: ```ruby -gem "imagekitio", git: "https://www.github.com/imagekit-developer/imagekit-ruby" +gem "imagekitio", git: "https://github.com/imagekit-developer/imagekit-ruby" ``` Alternatively, reference local copy of the repo: ```bash -$ git clone -- 'https://www.github.com/imagekit-developer/imagekit-ruby' '' +$ git clone -- 'https://github.com/imagekit-developer/imagekit-ruby' '' ``` ```ruby @@ -66,12 +66,6 @@ $ bundle exec rake ## 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. - -```bash -$ npx prism mock path/to/your/openapi.yml -``` - ```bash $ bundle exec rake test ``` diff --git a/Gemfile.lock b/Gemfile.lock index f0715a9..12efac0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -200,7 +200,6 @@ PLATFORMS arm64-darwin universal-darwin x86_64-darwin - x86_64-linux x86_64-linux-gnu x86_64-linux-musl @@ -226,4 +225,4 @@ DEPENDENCIES yard BUNDLED WITH - 2.7.1 + 2.4.1 diff --git a/README.md b/README.md index 390b3d7..4168b57 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,21 @@ -# ImageKit.io Ruby SDK +# Image Kit Ruby API library -The ImageKit Ruby library provides convenient access to the ImageKit REST API from any Ruby 3.2.0+ application. The library supports building and transforming URLs, generating signed URLs for secure content delivery, and handling file uploads. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [see below](https://github.com/imagekit-developer/imagekit-ruby#Sorbet) for usage with Sorbet. The standard library's `net/http` is used as the HTTP transport, with connection pooling via the `connection_pool` gem. +The Image Kit Ruby library provides convenient access to the Image Kit REST API from any Ruby 3.2.0+ application. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [see below](https://github.com/imagekit-developer/imagekit-ruby#Sorbet) for usage with Sorbet. The standard library's `net/http` is used as the HTTP transport, with connection pooling via the `connection_pool` gem. + +## MCP Server + +Use the Image Kit MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. + +[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40imagekit%2Fapi-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBpbWFnZWtpdC9hcGktbWNwIl0sImVudiI6eyJJTUFHRUtJVF9QUklWQVRFX0tFWSI6Ik15IFByaXZhdGUgS2V5IiwiT1BUSU9OQUxfSU1BR0VLSVRfSUdOT1JFU19USElTIjoiTXkgUGFzc3dvcmQiLCJJTUFHRUtJVF9XRUJIT09LX1NFQ1JFVCI6Ik15IFdlYmhvb2sgU2VjcmV0In19) +[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40imagekit%2Fapi-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40imagekit%2Fapi-mcp%22%5D%2C%22env%22%3A%7B%22IMAGEKIT_PRIVATE_KEY%22%3A%22My%20Private%20Key%22%2C%22OPTIONAL_IMAGEKIT_IGNORES_THIS%22%3A%22My%20Password%22%2C%22IMAGEKIT_WEBHOOK_SECRET%22%3A%22My%20Webhook%20Secret%22%7D%7D) + +> Note: You may need to set environment variables in your MCP client. ## Documentation -The official [ImageKit Ruby documentation](https://imagekit.io/docs/integration/ruby) provides complete integration guides and examples. - -If you're using Ruby on Rails, the [ImageKit Rails gem](https://github.com/imagekit-developer/imagekit-rails) builds on top of this SDK to provide [Rails-specific integrations](https://imagekit.io/docs/integration/ruby/ruby-on-rails) including Active Storage and view helpers. - -## Table of Contents - -- [Documentation](#documentation) -- [Installation](#installation) -- [Usage](#usage) - - [File uploads](#file-uploads) -- [URL Generation](#url-generation) - - [Basic URL generation](#basic-url-generation) - - [URL generation with transformations](#url-generation-with-transformations) - - [URL generation with image overlay](#url-generation-with-image-overlay) - - [URL generation with text overlay](#url-generation-with-text-overlay) - - [Signed URLs for secure delivery](#signed-urls-for-secure-delivery) - - [Chained transformations](#chained-transformations) - - [Using raw parameter for custom transformations](#using-raw-parameter-for-custom-transformations) -- [Helper Methods](#helper-methods) - - [Authentication parameters for client-side uploads](#authentication-parameters-for-client-side-uploads) - - [Responsive image attributes](#responsive-image-attributes) -- [Handling errors](#handling-errors) - - [Retries](#retries) - - [Timeouts](#timeouts) -- [Advanced concepts](#advanced-concepts) - - [BaseModel](#basemodel) - - [Making custom or undocumented requests](#making-custom-or-undocumented-requests) - - [Concurrency & connection pooling](#concurrency--connection-pooling) -- [Sorbet](#sorbet) - - [Enums](#enums) -- [Versioning](#versioning) -- [Requirements](#requirements) -- [Contributing](#contributing) +Documentation for releases of this gem can be found [on RubyDoc](https://gemdocs.org/gems/imagekitio). + +The REST API documentation can be found on [imagekit.io](https://imagekit.io/docs/api-reference). ## Installation @@ -53,478 +32,44 @@ gem "imagekitio", "~> 4.2.0" ## Usage ```ruby +require "bundler/setup" require "imagekitio" image_kit = Imagekitio::Client.new( private_key: ENV["IMAGEKIT_PRIVATE_KEY"], # This is the default and can be omitted + password: ENV["OPTIONAL_IMAGEKIT_IGNORES_THIS"] # This is the default and can be omitted ) response = image_kit.files.upload( - file: Pathname("/path/to/file"), + file: StringIO.new("https://www.example.com/public-url.jpg"), file_name: "file-name.jpg" ) -puts(response.file_id) +puts(response.videoCodec) ``` ### File uploads -Request parameters that correspond to file uploads can be passed as raw contents, a [`Pathname`](https://rubyapi.org/3.2/o/pathname) instance, or an `IO` stream. +Request parameters that correspond to file uploads can be passed as raw contents, a [`Pathname`](https://rubyapi.org/3.2/o/pathname) instance, [`StringIO`](https://rubyapi.org/3.2/o/stringio), or more. ```ruby require "pathname" -# Use `Pathname` to stream from disk (memory efficient, supports retries): +# Use `Pathname` to send the filename and/or avoid paging a large file into memory: response = image_kit.files.upload(file: Pathname("/path/to/file")) -# Or pass file contents directly +# Alternatively, pass file contents or a `StringIO` directly: response = image_kit.files.upload(file: File.read("/path/to/file")) # Or, to control the filename and/or content type: file = Imagekitio::FilePart.new(File.read("/path/to/file"), filename: "/path/to/file", content_type: "…") response = image_kit.files.upload(file: file) -puts(response.file_id) +puts(response.videoCodec) ``` Note that you can also pass a raw `IO` descriptor, but this disables retries, as the library can't be sure if the descriptor is a file or pipe (which cannot be rewound). -## URL Generation - -The ImageKit SDK provides a powerful `helper.build_url()` method for generating optimized image and video URLs with transformations. Here are examples ranging from simple URLs to complex transformations with overlays and signed URLs. - -### Basic URL generation - -Generate a simple URL without any transformations: - -```ruby -require "imagekitio" - -image_kit = Imagekitio::Client.new( - private_key: ENV["IMAGEKIT_PRIVATE_KEY"] -) - -# Basic URL without transformations -url = image_kit.helper.build_url({ - src: "/default-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id" -}) - -puts url -# Output: https://ik.imagekit.io/your_imagekit_id/default-image.jpg -``` - -You can also use absolute URLs: - -```ruby -url = image_kit.helper.build_url({ - src: "https://ik.imagekit.io/your_imagekit_id/default-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id" -}) -``` - -### URL generation with transformations - -Apply common transformations like resizing, cropping, and format conversion: - -```ruby -# URL with basic transformations -url = image_kit.helper.build_url({ - src: "/path/to/image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - transformation: [ - { - width: 400, - height: 300, - crop: :maintain_ratio, - quality: 80, - format_: :webp - } - ] -}) -# Output: https://ik.imagekit.io/your_imagekit_id/path/to/image.jpg?tr=w-400,h-300,c-maintain_ratio,q-80,f-webp -``` - -More transformation examples: - -```ruby -# Image resizing and cropping -url = image_kit.helper.build_url({ - src: "/product.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - transformation: [ - { - width: 800, - height: 600, - crop: :at_max, - focus: "auto" - } - ] -}) - -# Image effects -url = image_kit.helper.build_url({ - src: "/photo.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - transformation: [ - { - blur: 10, - grayscale: true, - radius: 20 - } - ] -}) - -# Format and quality optimization -url = image_kit.helper.build_url({ - src: "/image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - transformation: [ - { - format_: :auto, - quality: 85, - progressive: true - } - ] -}) -``` - -### URL generation with image overlay - -Add image overlays to your base image: - -```ruby -# URL with image overlay -url = image_kit.helper.build_url({ - src: "/path/to/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - transformation: [ - { - width: 500, - height: 400, - overlay: { - type: :image, - input: "/path/to/overlay-logo.png", - position: { - x: 10, - y_: 10 - }, - transformation: [ - { - width: 100, - height: 50 - } - ] - } - } - ] -}) -# Output: URL with image overlay positioned at x:10, y:10 -``` - -### URL generation with text overlay - -Add customized text overlays: - -```ruby -# URL with text overlay -url = image_kit.helper.build_url({ - src: "/path/to/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - transformation: [ - { - width: 600, - height: 400, - overlay: { - type: :text, - text: "Sample Text Overlay", - position: { - x: 50, - y_: 50, - focus: :center - }, - transformation: [ - { - font_size: 40, - font_family: "Arial", - font_color: "FFFFFF", - typography: "b" # bold - } - ] - } - } - ] -}) -# Output: URL with bold white Arial text overlay at center position -``` - -You can combine multiple overlays for complex compositions: - -```ruby -# URL with multiple overlays (text + image) -url = image_kit.helper.build_url({ - src: "/path/to/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - transformation: [ - { - width: 800, - height: 600, - overlay: { - type: :text, - text: "Header Text", - position: { x: 20, y_: 20 }, - transformation: [{ font_size: 30, font_color: "000000" }] - } - }, - { - overlay: { - type: :image, - input: "/watermark.png", - position: { focus: :bottom_right }, - transformation: [{ width: 100, opacity: 70 }] - } - } - ] -}) -# Output: URL with text overlay at top-left and semi-transparent watermark at bottom-right -``` - -### Signed URLs for secure delivery - -Generate signed URLs that expire after a specified time for secure content delivery: - -```ruby -# Generate a signed URL that expires in 1 hour (3600 seconds) -url = image_kit.helper.build_url({ - src: "/private/secure-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - transformation: [ - { - width: 400, - height: 300, - quality: 90 - } - ], - signed: true, - expires_in: 3600 # URL expires in 1 hour -}) -# Output: URL with signature parameters (?ik-t=timestamp&ik-s=signature) - -# Generate a signed URL that doesn't expire -url = image_kit.helper.build_url({ - src: "/private/secure-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - signed: true - # No expires_in means the URL won't expire -}) -# Output: URL with signature parameter (?ik-s=signature) -``` - -### Chained transformations - -Apply multiple transformation steps by passing multiple transformation objects. Each transformation is applied sequentially: - -```ruby -# First resize, then apply effects -url = image_kit.helper.build_url({ - src: "/default-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - transformation: [ - { - width: 400, - height: 300 - }, - { - rotation: 90, - blur: 5 - } - ] -}) -# Output: https://ik.imagekit.io/your_imagekit_id/default-image.jpg?tr=w-400,h-300:rt-90,bl-5 -``` - -### Using raw parameter for custom transformations - -ImageKit frequently adds new transformation parameters that might not yet be documented in the SDK. You can use the `raw` parameter to access these features or create custom transformation strings: - -```ruby -# Using raw parameter for custom transformations -url = image_kit.helper.build_url({ - src: "/path/to/image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - transformation: [ - { - width: 400, - height: 300, - raw: "something-new" - } - ] -}) -# Output: https://ik.imagekit.io/your_imagekit_id/path/to/image.jpg?tr=w-400,h-300,something-new -``` - -You can control where transformations appear in the URL: - -```ruby -# Add transformations to the URL path instead of query parameters -url = image_kit.helper.build_url({ - src: "/default-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - transformation_position: :path, - transformation: [ - { - width: 400, - height: 300 - } - ] -}) -# Output: https://ik.imagekit.io/your_imagekit_id/tr:w-400,h-300/default-image.jpg -``` - -Add custom query parameters: - -```ruby -url = image_kit.helper.build_url({ - src: "/default-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - query_parameters: { - version: "1", - cache: "max" - } -}) -``` - -## Helper Methods - -The SDK provides several helper methods for common ImageKit operations. - -### Authentication parameters for client-side uploads - -Generate authentication parameters for secure client-side file uploads. These parameters allow you to securely upload files directly from the browser without exposing your private API key: - -```ruby -require "imagekitio" - -image_kit = Imagekitio::Client.new( - private_key: ENV["IMAGEKIT_PRIVATE_KEY"] -) - -# Generate authentication parameters with default expiry (30 minutes) -auth_params = image_kit.helper.get_authentication_parameters - -puts auth_params -# Output: { token: "unique-token", expire: 1234567890, signature: "signature-hash" } -``` - -Customize the token and expiration: - -```ruby -# Custom token and expiry (1 hour from now) -auth_params = image_kit.helper.get_authentication_parameters( - token: "my-custom-token", - expire: Time.now.to_i + 3600 -) -# Output: { token: "my-custom-token", expire: 1234567890, signature: "generated-signature" } -``` - -These authentication parameters can be used in client-side upload forms to securely upload files without exposing your private API key. - -### Responsive image attributes - -Generate responsive image attributes for HTML `` tags. This creates optimized `srcset` and `sizes` attributes for responsive images: - -```ruby -# Width-based responsive images (generates w descriptors) -attrs = image_kit.helper.get_responsive_image_attributes({ - src: "/default-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - sizes: "(min-width: 768px) 50vw, 100vw", - transformation: [ - { - quality: 80, - format_: :auto - } - ] -}) - -puts attrs.src -# Largest candidate URL - -puts attrs.src_set -# URL1 640w, URL2 750w, URL3 1080w, ... - -puts attrs.sizes -# (min-width: 768px) 50vw, 100vw -``` - -DPR-based responsive images (generates x descriptors): - -```ruby -# When width is provided without sizes, generates 1x and 2x variants -attrs = image_kit.helper.get_responsive_image_attributes({ - src: "/profile.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - width: 400, - transformation: [ - { - quality: 85 - } - ] -}) - -puts attrs.src_set -# URL1 1x, URL2 2x - -puts attrs.width -# 400 -``` - -Custom breakpoints for device widths: - -```ruby -attrs = image_kit.helper.get_responsive_image_attributes({ - src: "/default-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - sizes: "100vw", - device_breakpoints: [320, 640, 1024, 1920], - image_breakpoints: [16, 32, 64], - transformation: [ - { - crop: :at_max - } - ] -}) -``` - -The returned attributes can be directly used in your HTML: - -```erb -Responsive image -``` - -Generate signed responsive image URLs: - -```ruby -# Generate signed responsive image URLs -attrs = image_kit.helper.get_responsive_image_attributes({ - src: "/default-image.jpg", - url_endpoint: "https://ik.imagekit.io/your_imagekit_id", - sizes: "100vw", - signed: true, - expires_in: 3600, - transformation: [ - { - quality: 80 - } - ] -}) -``` - ### Handling errors When the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of `Imagekitio::Errors::APIError` will be thrown: @@ -532,7 +77,7 @@ When the library is unable to connect to the API, or if the API returns a non-su ```ruby begin file = image_kit.files.upload( - file: File.read("/path/to/file.jpg"), + file: StringIO.new("https://www.example.com/public-url.jpg"), file_name: "file-name.jpg" ) rescue Imagekitio::Errors::APIConnectionError => e @@ -578,7 +123,7 @@ image_kit = Imagekitio::Client.new( # Or, configure per-request: image_kit.files.upload( - file: File.read("/path/to/file.jpg"), + file: StringIO.new("https://www.example.com/public-url.jpg"), file_name: "file-name.jpg", request_options: {max_retries: 5} ) @@ -596,7 +141,7 @@ image_kit = Imagekitio::Client.new( # Or, configure per-request: image_kit.files.upload( - file: File.read("/path/to/file.jpg"), + file: StringIO.new("https://www.example.com/public-url.jpg"), file_name: "file-name.jpg", request_options: {timeout: 5} ) @@ -631,7 +176,7 @@ Note: the `extra_` parameters of the same name overrides the documented paramete ```ruby response = image_kit.files.upload( - file: File.read("/path/to/file.jpg"), + file: StringIO.new("https://www.example.com/public-url.jpg"), file_name: "file-name.jpg", request_options: { extra_query: {my_query_parameter: value}, @@ -679,7 +224,7 @@ You can provide typesafe request parameters like so: ```ruby image_kit.files.upload( - file: File.read("/path/to/file.jpg"), + file: StringIO.new("https://www.example.com/public-url.jpg"), file_name: "file-name.jpg" ) ``` @@ -689,13 +234,13 @@ Or, equivalently: ```ruby # Hashes work, but are not typesafe: image_kit.files.upload( - file: File.read("/path/to/file.jpg"), + file: StringIO.new("https://www.example.com/public-url.jpg"), file_name: "file-name.jpg" ) # You can also splat a full Params class: params = Imagekitio::FileUploadParams.new( - file: File.read("/path/to/file.jpg"), + file: StringIO.new("https://www.example.com/public-url.jpg"), file_name: "file-name.jpg" ) image_kit.files.upload(**params) diff --git a/SECURITY.md b/SECURITY.md index 2ed9bbb..8e64327 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,9 +16,9 @@ before making any information public. ## Reporting Non-SDK Related Security Issues If you encounter security issues that are not directly related to SDKs but pertain to the services -or products provided by ImageKit, please follow the respective company's security reporting guidelines. +or products provided by Image Kit, please follow the respective company's security reporting guidelines. -### ImageKit Terms and Policies +### Image Kit Terms and Policies Please contact developer@imagekit.io for any questions or concerns regarding the security of our services. diff --git a/imagekitio.gemspec b/imagekitio.gemspec index 32c565a..ede1aaf 100644 --- a/imagekitio.gemspec +++ b/imagekitio.gemspec @@ -5,8 +5,8 @@ require_relative "lib/imagekitio/version" Gem::Specification.new do |s| s.name = "imagekitio" s.version = Imagekitio::VERSION - s.summary = "Ruby library to access the ImageKit API" - s.authors = ["ImageKit"] + s.summary = "Ruby library to access the Image Kit API" + s.authors = ["Image Kit"] s.email = "developer@imagekit.io" s.homepage = "https://gemdocs.org/gems/imagekitio" s.metadata["homepage_uri"] = s.homepage diff --git a/lib/imagekitio.rb b/lib/imagekitio.rb index 2fd3ff6..7aafe2f 100644 --- a/lib/imagekitio.rb +++ b/lib/imagekitio.rb @@ -188,4 +188,3 @@ require_relative "imagekitio/resources/folders/job" require_relative "imagekitio/resources/saved_extensions" require_relative "imagekitio/resources/webhooks" -require_relative "imagekitio/helpers/helper" diff --git a/lib/imagekitio/client.rb b/lib/imagekitio/client.rb index 2992be4..2c3d632 100644 --- a/lib/imagekitio/client.rb +++ b/lib/imagekitio/client.rb @@ -52,9 +52,6 @@ class Client < Imagekitio::Internal::Transport::BaseClient # @return [Imagekitio::Resources::Webhooks] attr_reader :webhooks - # @return [Imagekitio::Helper] - attr_reader :helper - # @api private # # @return [Hash{String=>String}] @@ -103,7 +100,7 @@ def initialize( base_url ||= "https://api.imagekit.io" - if private_key.nil? || private_key.to_s.empty? + if private_key.nil? raise ArgumentError.new("private_key is required, and can be set via environ: \"IMAGEKIT_PRIVATE_KEY\"") end @@ -127,7 +124,6 @@ def initialize( @accounts = Imagekitio::Resources::Accounts.new(client: self) @beta = Imagekitio::Resources::Beta.new(client: self) @webhooks = Imagekitio::Resources::Webhooks.new(client: self) - @helper = Imagekitio::Helper.new(client: self) end end end diff --git a/lib/imagekitio/helpers/crypto_utils.rb b/lib/imagekitio/helpers/crypto_utils.rb deleted file mode 100644 index 1d0be44..0000000 --- a/lib/imagekitio/helpers/crypto_utils.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: true - -require "openssl" -require "digest" - -module Imagekitio - # @api private - # Crypto utilities for ImageKit SDK - # Provides HMAC-SHA1 functionality for URL signing and authentication - module CryptoUtils - class << self - # Creates an HMAC-SHA1 hash - # - # @param key [String] The secret key for HMAC generation - # @param data [String] The data to be signed - # @return [String] Hex-encoded HMAC-SHA1 hash - # @raise [StandardError] if HMAC generation fails - def create_hmac_sha1(key, data) - OpenSSL::HMAC.hexdigest("SHA1", key, data) - rescue StandardError => e - raise StandardError, "Failed to generate HMAC-SHA1 signature: #{e.message}" - end - end - end -end diff --git a/lib/imagekitio/helpers/helper.rb b/lib/imagekitio/helpers/helper.rb deleted file mode 100644 index 3547511..0000000 --- a/lib/imagekitio/helpers/helper.rb +++ /dev/null @@ -1,693 +0,0 @@ -# frozen_string_literal: true - -require_relative "transformation_utils" -require_relative "crypto_utils" -require_relative "uuid_utils" - -module Imagekitio - class Helper - TRANSFORMATION_PARAMETER = "tr" - SIGNATURE_PARAMETER = "ik-s" - TIMESTAMP_PARAMETER = "ik-t" - DEFAULT_TIMESTAMP = 9_999_999_999 - SIMPLE_OVERLAY_PATH_REGEX = %r{^[a-zA-Z0-9\-._/ ]*$} - SIMPLE_OVERLAY_TEXT_REGEX = /^[a-zA-Z0-9\-._ ]*$/ - - private_constant :TRANSFORMATION_PARAMETER, - :SIGNATURE_PARAMETER, - :TIMESTAMP_PARAMETER, - :DEFAULT_TIMESTAMP, - :SIMPLE_OVERLAY_PATH_REGEX, - :SIMPLE_OVERLAY_TEXT_REGEX - - # Builds a URL with transformations applied - # - # @param options [Imagekitio::Models::SrcOptions] Options for generating ImageKit URLs with transformations - # @return [String] The built URL with transformations - def build_url(options) - # Convert model to hash - all inputs are expected to be BaseModel objects - opts = options.to_h - - # Set defaults - opts[:url_endpoint] ||= "" - opts[:src] ||= "" - opts[:transformation_position] ||= :query - - return "" if opts[:src].nil? || opts[:src].empty? - - src = opts[:src].to_s - is_absolute_url = src.start_with?("http://", "https://") - - begin - if is_absolute_url - url_obj = URI.parse(src) - is_src_parameter_used_for_url = true - else - url_obj = URI.parse(opts[:url_endpoint].to_s) - end - rescue URI::InvalidURIError - return "" - end - - # Add query parameters - query_params = opts[:query_parameters] || {} - existing_params = CGI.parse(url_obj.query || "") - query_params.each do |key, value| - existing_params[key.to_s] = [value.to_s] - end - - # Build transformation string - transformation_string = build_transformation_string(opts[:transformation]) - - add_as_query = Imagekitio::TransformationUtils.add_as_query_parameter?(opts) || - is_src_parameter_used_for_url - transformation_placeholder = "PLEASEREPLACEJUSTBEFORESIGN" - - unless is_absolute_url - # For non-absolute URLs, construct the path - endpoint_path = url_obj.path - path_parts = [] - - # Add endpoint path if it's not empty - if !endpoint_path.empty? && endpoint_path != "/" - path_parts << endpoint_path - end - - if !transformation_string.empty? && !add_as_query - path_parts << "#{TRANSFORMATION_PARAMETER}#{Imagekitio::TransformationUtils.get_chain_transform_delimiter}#{transformation_placeholder}" - end - - path_parts << src - url_obj.path = path_join(path_parts) - end - - # Build query string - unless existing_params.empty? - url_obj.query = existing_params.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v.first)}" }.join("&") - end - - # Build final URL - final_url = url_obj.to_s - - # Add transformation parameter manually to avoid URL encoding - if !transformation_string.empty? && add_as_query - separator = url_obj.query && !url_obj.query.empty? ? "&" : "?" - final_url = "#{final_url}#{separator}#{TRANSFORMATION_PARAMETER}=#{transformation_placeholder}" - end - - # Replace placeholder with actual transformation string - unless transformation_string.empty? - final_url = final_url.gsub(transformation_placeholder, transformation_string) - end - - # Sign the URL if needed - if opts[:signed] == true || (opts[:expires_in] && opts[:expires_in].to_i.positive?) - expiry_timestamp = get_signature_timestamp(opts[:expires_in]) - - url_signature = get_signature( - private_key: @client.private_key, - url: final_url, - url_endpoint: opts[:url_endpoint].to_s, - expiry_timestamp: expiry_timestamp - ) - - # Add signature parameters - final_url_uri = URI.parse(final_url) - has_existing_params = final_url_uri.query && !final_url_uri.query.empty? - separator = has_existing_params ? "&" : "?" - - if expiry_timestamp && expiry_timestamp != DEFAULT_TIMESTAMP - final_url = "#{final_url}#{separator}#{TIMESTAMP_PARAMETER}=#{expiry_timestamp}" - final_url = "#{final_url}&#{SIGNATURE_PARAMETER}=#{url_signature}" - else - final_url = "#{final_url}#{separator}#{SIGNATURE_PARAMETER}=#{url_signature}" - end - end - - final_url - end - - # Generates transformation string from transformation objects - # - # @param transformations [Array] Array of transformation objects - # @return [String] The transformation string (e.g., "w-400,h-300") - def build_transformation_string(transformations) - return "" unless transformations.is_a?(Array) - - parsed_transforms = [] - - # rubocop:disable Metrics/BlockLength - transformations.each do |transform| - next unless transform - - # Convert model to hash - all transformation inputs are expected to be BaseModel objects - current_transform = transform.to_h - - parsed_transform_step = [] - - # rubocop:disable Metrics/BlockLength - current_transform.each do |key, value| - next if value.nil? || value.to_s.empty? - - # Handle overlay separately - if key.to_s == "overlay" && value - # Pass model object directly to process_overlay - raw_string = process_overlay(value) - if raw_string && !raw_string.strip.empty? - parsed_transform_step << raw_string - end - next - end - - transform_key = Imagekitio::TransformationUtils.get_transform_key(key) - transform_key = key.to_s if transform_key.empty? - - next if transform_key.empty? - - # Handle special boolean effects - boolean_effects = %w[e-grayscale e-contrast e-removedotbg e-bgremove e-upscale e-retouch e-genvar] - if boolean_effects.include?(transform_key) - if value == true || value == "-" || value == "true" - parsed_transform_step << transform_key - end - next - end - - # Handle effects that can be boolean or have values - value_effects = %w[e-sharpen e-shadow e-gradient e-usm e-dropshadow] - if value_effects.include?(transform_key) && - (value.to_s.strip.empty? || value == true || value == "true") - parsed_transform_step << transform_key - next - end - - # Handle raw parameter - if key.to_s == "raw" - parsed_transform_step << value.to_s - next - end - - # Handle special cases for di and ff (need special encoding) - if %w[di ff].include?(transform_key) - processed_value = remove_leading_slash(remove_trailing_slash(value.to_s)) - processed_value = processed_value.gsub("/", "@@") - value = processed_value - end - - # Handle streaming resolutions array - if transform_key == "sr" && value.is_a?(Array) - value = value.join("_") - end - - # Special case for trim with empty string - if transform_key == "t" && value.to_s.strip.empty? - value = "true" - end - - # Convert numeric values to integers if they're whole numbers - if value.is_a?(Numeric) - value = value.to_i if value == value.to_i - end - - parsed_transform_step << "#{transform_key}#{Imagekitio::TransformationUtils.get_transform_key_value_delimiter}#{value}" - end - # rubocop:enable Metrics/BlockLength - - unless parsed_transform_step.empty? - parsed_transforms << parsed_transform_step.join(Imagekitio::TransformationUtils.get_transform_delimiter) - end - end - # rubocop:enable Metrics/BlockLength - - parsed_transforms.join(Imagekitio::TransformationUtils.get_chain_transform_delimiter) - end - - # Generates authentication parameters for client-side file uploads using ImageKit's Upload API V1. - # - # This method creates the required authentication signature that allows secure file uploads - # directly from the browser or mobile applications without exposing your private API key. - # The generated parameters include a unique token, expiration timestamp, and HMAC signature. - # - # @param token [String, nil] Custom token for the upload session. If not provided, a UUID v4 will be generated automatically. - # @param expire [Integer, nil] Expiration time in seconds from now. If not provided, defaults to 1800 seconds (30 minutes). - # @return [Hash{Symbol => String, Integer}] Authentication parameters object containing: - # - :token (String): Unique identifier for this upload session - # - :expire (Integer): Unix timestamp when these parameters expire - # - :signature (String): HMAC-SHA1 signature for authenticating the upload - def get_authentication_parameters(token: nil, expire: nil) - default_time_diff = 60 * 30 - default_expire = Time.now.to_i + default_time_diff - - # Handle falsy values - empty string and nil should generate new token - final_token = token.nil? || token.to_s.empty? ? generate_token : token - # Handle falsy values - nil and 0 should use default expire - final_expire = expire.nil? || expire.zero? ? default_expire : expire - - get_authentication_parameters_internal(final_token, final_expire, @client.private_key) - end - - # Generates responsive image attributes for use in HTML tags. - # - # This method creates optimized srcset and sizes attributes for responsive images, - # enabling browsers to select the most appropriate image size based on the device's - # screen width and resolution. Supports three strategies: - # - Width-based (w descriptors): When sizes attribute is provided - # - DPR-based (x descriptors): When width is provided without sizes - # - Fallback (w descriptors): Uses device breakpoints when neither is provided - # - # @param options [Imagekitio::Models::GetImageAttributesOptions] Options for generating responsive image attributes - # @return [Imagekitio::Models::ResponsiveImageAttributes] Responsive image attributes suitable for an HTML element - def get_responsive_image_attributes(options) - # Convert model to hash for easier access - opts = options.is_a?(Imagekitio::Internal::Type::BaseModel) ? options.to_h : options - - # Default breakpoint pools - default_device_breakpoints = [640, 750, 828, 1080, 1200, 1920, 2048, 3840] - default_image_breakpoints = [16, 32, 48, 64, 96, 128, 256, 384] - - # Extract options - src = opts[:src] - url_endpoint = opts[:url_endpoint] - width = opts[:width] - sizes = opts[:sizes] - device_breakpoints = opts[:device_breakpoints] || default_device_breakpoints - image_breakpoints = opts[:image_breakpoints] || default_image_breakpoints - transformation = opts[:transformation] || [] - transformation_position = opts[:transformation_position] - query_parameters = opts[:query_parameters] - expires_in = opts[:expires_in] - signed = opts[:signed] - - # Sort and merge breakpoints - sorted_device_breakpoints = device_breakpoints.sort - sorted_image_breakpoints = image_breakpoints.sort - all_breakpoints = (sorted_image_breakpoints + sorted_device_breakpoints).sort.uniq - - # Compute candidate widths and descriptor kind - result = compute_candidate_widths( - all_breakpoints: all_breakpoints, - device_breakpoints: sorted_device_breakpoints, - explicit_width: width, - sizes_attr: sizes - ) - candidates = result[:candidates] - descriptor_kind = result[:descriptor_kind] - - # Helper to build a single ImageKit URL - build_url_fn = lambda do |w| - build_url( - Imagekitio::Models::SrcOptions.new( - src: src, - url_endpoint: url_endpoint, - query_parameters: query_parameters, - transformation_position: transformation_position, - expires_in: expires_in, - signed: signed, - transformation: transformation + [ - Imagekitio::Models::Transformation.new(width: w, crop: "at_max") # never upscale beyond original - ] - ) - ) - end - - # Build srcset - src_set_entries = candidates.map.with_index do |w, i| - # Ensure width is an integer for proper descriptor format (e.g., "640w" not "640.0w") - width_int = w.to_i - descriptor = descriptor_kind == :w ? "#{width_int}w" : "#{i + 1}x" - "#{build_url_fn.call(width_int)} #{descriptor}" - end - src_set = src_set_entries.empty? ? nil : src_set_entries.join(", ") - - final_sizes = sizes || (descriptor_kind == :w ? "100vw" : nil) - - # Build and return ResponsiveImageAttributes model - Imagekitio::Models::ResponsiveImageAttributes.new( - src: build_url_fn.call(candidates.last.to_i), # largest candidate as integer - src_set: src_set, - sizes: final_sizes, - width: width - ) - end - - # @api private - # - # @param client [Imagekitio::Client] - def initialize(client:) - @client = client - end - - private - - # Compute candidate widths for responsive images. - # Implements three strategies: - # 1. Width-based srcSet (w) when sizes attribute contains vw units - # 2. Fallback to device breakpoints when no width or sizes provided - # 3. DPR-based srcSet (x) with 1x and 2x variants when width is provided - def compute_candidate_widths( - all_breakpoints:, - device_breakpoints:, - explicit_width: nil, - sizes_attr: nil - ) - # Strategy 1: Width-based srcSet (w) using viewport vw hints - if sizes_attr - vw_tokens = sizes_attr.scan(/(?:^|\s)(1?\d{1,2})vw/).flatten.map(&:to_i) - - if vw_tokens.any? - # Find the smallest vw percentage - smallest_ratio = vw_tokens.min / 100.0 - # Calculate minimum required pixels - min_required_px = device_breakpoints.first * smallest_ratio - # Filter breakpoints >= min_required_px - candidates = all_breakpoints.select { |bp| bp >= min_required_px } - return {candidates: candidates, descriptor_kind: :w} - end - - # No usable vw found: fallback to all breakpoints - return {candidates: all_breakpoints, descriptor_kind: :w} - end - - # Strategy 2: Fallback using device breakpoints if no explicit width - return {candidates: device_breakpoints, descriptor_kind: :w} unless explicit_width - - # Strategy 3: Use 1x and 2x nearest breakpoints for x descriptor - # Find the first breakpoint >= target (or use the largest) - nearest = lambda do |target| - all_breakpoints.find { |bp| bp >= target } || all_breakpoints.last - end - - # Generate unique 1x and 2x variants - unique = [nearest.call(explicit_width), nearest.call(explicit_width * 2)].uniq - - {candidates: unique, descriptor_kind: :x} - end - - # Generate a 32-character hex token - def generate_token - # Generate 16 random bytes and convert to hex (32 characters) - require("securerandom") - SecureRandom.hex(16) - end - - # Internal method to generate authentication parameters - def get_authentication_parameters_internal(token, expire, private_key) - auth_parameters = { - token: token, - expire: expire, - signature: "" - } - - signature = Imagekitio::CryptoUtils.create_hmac_sha1(private_key, token.to_s + expire.to_s) - auth_parameters[:signature] = signature - - auth_parameters - end - - # Remove trailing slash from string - def remove_trailing_slash(str) - return str unless str.is_a?(String) && str.end_with?("/") - str.chomp("/") - end - - # Remove leading slash from string - def remove_leading_slash(str) - return str unless str.is_a?(String) && str.start_with?("/") - str[1..] - end - - # RFC 3986 path encoding - matches Node.js encodeURIPath exactly - # From Node.js: str.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent) - def encode_uri_path(str) - # Only encode characters that are NOT in the RFC 3986 path character set - # unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" - # sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" - # pchar = unreserved / pct-encoded / sub-delims / ":" / "@" - str.gsub(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/) { |match| CGI.escape(match) } - end - - # Join path parts (Node.js pathJoin algorithm without encoding) - def path_join(parts, separator = "/") - return "" if parts.nil? || parts.empty? - - # Clean up parts and join - cleaned_parts = [] - - parts.each do |part| - part = part.to_s.strip - next if part.empty? - - # Remove leading slashes from all parts - part = part[1..] while part.start_with?(separator) - - # Remove trailing slashes from all parts - part = part[0..-2] while part.end_with?(separator) - - cleaned_parts << part unless part.empty? - end - - return "" if cleaned_parts.empty? - - # Join with separator and add leading slash (Node.js style) - result = separator + cleaned_parts.join(separator) - - # Apply encoding to special characters only, preserving path structure - result.gsub(/[^\x00-\x7F]/) { |char| CGI.escape(char) } - end - - # Process overlay transformation (full implementation) - def process_overlay(overlay) - return "" unless overlay - - # Support both BaseModel objects and plain hashes - type = if overlay.is_a?(Hash) - overlay[:type] || overlay["type"] - else - overlay.type - end - return "" unless type - - # Determine overlay type based on explicit type field - case type.to_s - when "text" - process_text_overlay(overlay) - when "image" - process_image_overlay(overlay) - when "video" - process_video_overlay(overlay) - when "subtitle" - process_subtitle_overlay(overlay) - when "solidColor" - process_solid_color_overlay(overlay) - else - "" - end - end - - # Process input path for image/video/subtitle overlays (matching Node.js processInputPath) - def process_input_path(str, encoding) - # Remove leading and trailing slashes - str = remove_trailing_slash(remove_leading_slash(str)) - - case encoding.to_s - when "plain" - "i-#{str.gsub('/', '@@')}" - when "base64" - "ie-#{CGI.escape(Base64.strict_encode64(str))}" - else # auto - if str.match?(SIMPLE_OVERLAY_PATH_REGEX) - "i-#{str.gsub('/', '@@')}" - else - "ie-#{CGI.escape(Base64.strict_encode64(str))}" - end - end - end - - # Process text content for text overlays (matching Node.js processText) - def process_text(str, encoding) - case encoding.to_s - when "plain" - "i-#{uri_encode(str)}" - when "base64" - "ie-#{uri_encode(Base64.strict_encode64(str))}" - else # auto - if str.match?(SIMPLE_OVERLAY_TEXT_REGEX) - "i-#{uri_encode(str)}" - else - "ie-#{uri_encode(Base64.strict_encode64(str))}" - end - end - end - - # URI encode like JavaScript's encodeURIComponent (uses %20 instead of +) - def uri_encode(str) - CGI.escape(str).gsub("+", "%20") - end - - # Process text overlay - def process_text_overlay(overlay) - text = safe_get(overlay, :text) - return "" unless text && !text.to_s.empty? - - parts = ["l-text"] - - # Handle encoding using the processText function - encoding = safe_get(overlay, :encoding) || "auto" - parts << process_text(text, encoding) - - # Add other overlay properties (position, timing, transformations) - add_overlay_properties(parts, overlay) - - parts << "l-end" - parts.join(",") - end - - # Process image overlay - def process_image_overlay(overlay) - input = safe_get(overlay, :input) - return "" unless input && !input.to_s.empty? - - parts = ["l-image"] - - # Handle encoding using the process_input_path function - encoding = safe_get(overlay, :encoding) || "auto" - parts << process_input_path(input, encoding) - - # Add other overlay properties - add_overlay_properties(parts, overlay) - - parts << "l-end" - parts.join(",") - end - - # Process video overlay - def process_video_overlay(overlay) - input = safe_get(overlay, :input) - return "" unless input && !input.to_s.empty? - - parts = ["l-video"] - - # Handle encoding using the process_input_path function - encoding = safe_get(overlay, :encoding) || "auto" - parts << process_input_path(input, encoding) - - # Add other overlay properties - add_overlay_properties(parts, overlay) - - parts << "l-end" - parts.join(",") - end - - # Process subtitle overlay - def process_subtitle_overlay(overlay) - input = safe_get(overlay, :input) - return "" unless input && !input.to_s.empty? - - parts = ["l-subtitles"] - - # Handle encoding using the process_input_path function - encoding = safe_get(overlay, :encoding) || "auto" - parts << process_input_path(input, encoding) - - # Add other overlay properties - add_overlay_properties(parts, overlay) - - parts << "l-end" - parts.join(",") - end - - # Process solid color overlay - def process_solid_color_overlay(overlay) - color = safe_get(overlay, :color) - return "" unless color && !color.to_s.empty? - - parts = ["l-image", "i-ik_canvas", "bg-#{color}"] - - # Add other overlay properties - add_overlay_properties(parts, overlay) - - parts << "l-end" - parts.join(",") - end - - # Safe property access for model objects and hashes - def safe_get(obj, key) - return nil unless obj - - # Support both BaseModel objects and plain hashes - if obj.is_a?(Hash) - obj[key.to_sym] || obj[key.to_s] - elsif obj.respond_to?(key.to_sym) - obj.send(key.to_sym) - else - nil - end - end - - # Add overlay properties like position, timing, transformations (matching Node.js) - def add_overlay_properties(parts, overlay) - # Add layer_mode property - layer_mode = safe_get(overlay, :layer_mode) - parts << "lm-#{layer_mode}" if layer_mode - - # Add position properties - position = safe_get(overlay, :position) - if position - x = safe_get(position, :x) - y = safe_get(position, :y_) - focus = safe_get(position, :focus) - - parts << "lx-#{x}" if x - parts << "ly-#{y}" if y - parts << "lfo-#{focus}" if focus - end - - # Add timing properties - timing = safe_get(overlay, :timing) - if timing - start = safe_get(timing, :start) - end_time = safe_get(timing, :end_) - duration = safe_get(timing, :duration) - - parts << "lso-#{start.to_i}" if start - parts << "leo-#{end_time.to_i}" if end_time - parts << "ldu-#{duration}" if duration - end - - # Add transformation properties - transformations = safe_get(overlay, :transformation) - return unless transformations && transformations.is_a?(Array) - transformation_string = build_transformation_string(transformations) - return unless transformation_string && !transformation_string.strip.empty? - parts << transformation_string - end - - # Calculate expiry timestamp for URL signing - def get_signature_timestamp(seconds) - return DEFAULT_TIMESTAMP unless seconds && seconds.to_i.positive? - - sec = seconds.to_i - return DEFAULT_TIMESTAMP if sec <= 0 - - Time.now.to_i + sec - end - - # Generate HMAC-SHA1 signature for URL signing - def get_signature(private_key:, url:, url_endpoint:, expiry_timestamp:) - return "" if private_key.nil? || private_key.empty? || url.nil? || url.empty? || url_endpoint.nil? - - # Create string to sign: relative path + expiry timestamp - endpoint_with_slash = add_trailing_slash(url_endpoint) - string_to_sign = url.gsub(endpoint_with_slash, "") + expiry_timestamp.to_s - - Imagekitio::CryptoUtils.create_hmac_sha1(private_key, string_to_sign) - end - - # Add trailing slash to string if not present - def add_trailing_slash(str) - return str unless str.is_a?(String) - return str if str.end_with?("/") - "#{str}/" - end - end -end diff --git a/lib/imagekitio/helpers/transformation_utils.rb b/lib/imagekitio/helpers/transformation_utils.rb deleted file mode 100644 index 45c02a0..0000000 --- a/lib/imagekitio/helpers/transformation_utils.rb +++ /dev/null @@ -1,171 +0,0 @@ -# frozen_string_literal: true - -module Imagekitio - # @api private - # Transformation utilities for building ImageKit URLs - # Ported from the Node.js SDK - module TransformationUtils - # Constants for transformation parsing - QUERY_TRANSFORMATION_POSITION = :query - PATH_TRANSFORMATION_POSITION = :path - CHAIN_TRANSFORM_DELIMITER = ":" - TRANSFORM_DELIMITER = "," - TRANSFORM_KEY_VALUE_DELIMITER = "-" - - # Supported transformations mapping - # Based on https://imagekit.io/docs/transformations - SUPPORTED_TRANSFORMS = { - # Basic sizing & layout - "width" => "w", - "height" => "h", - "aspect_ratio" => "ar", - "aspectRatio" => "ar", - "background" => "bg", - "border" => "b", - "crop" => "c", - "crop_mode" => "cm", - "cropMode" => "cm", - "dpr" => "dpr", - "focus" => "fo", - "quality" => "q", - "x" => "x", - "x_center" => "xc", - "xCenter" => "xc", - "y" => "y", - "y_" => "y", - "y_center" => "yc", - "yCenter" => "yc", - "format" => "f", - "format_" => "f", - "video_codec" => "vc", - "videoCodec" => "vc", - "audio_codec" => "ac", - "audioCodec" => "ac", - "radius" => "r", - "rotation" => "rt", - "blur" => "bl", - "named" => "n", - "default_image" => "di", - "defaultImage" => "di", - "flip" => "fl", - "original" => "orig", - "start_offset" => "so", - "startOffset" => "so", - "end_offset" => "eo", - "endOffset" => "eo", - "duration" => "du", - "streaming_resolutions" => "sr", - "streamingResolutions" => "sr", - - # AI & advanced effects - "grayscale" => "e-grayscale", - "ai_upscale" => "e-upscale", - "aiUpscale" => "e-upscale", - "ai_retouch" => "e-retouch", - "aiRetouch" => "e-retouch", - "ai_variation" => "e-genvar", - "aiVariation" => "e-genvar", - "ai_drop_shadow" => "e-dropshadow", - "aiDropShadow" => "e-dropshadow", - "ai_change_background" => "e-changebg", - "aiChangeBackground" => "e-changebg", - "ai_remove_background" => "e-bgremove", - "aiRemoveBackground" => "e-bgremove", - "ai_remove_background_external" => "e-removedotbg", - "aiRemoveBackgroundExternal" => "e-removedotbg", - "ai_edit" => "e-edit", - "aiEdit" => "e-edit", - "contrast_stretch" => "e-contrast", - "contrastStretch" => "e-contrast", - "shadow" => "e-shadow", - "sharpen" => "e-sharpen", - "unsharp_mask" => "e-usm", - "unsharpMask" => "e-usm", - "gradient" => "e-gradient", - "color_replace" => "cr", - "colorReplace" => "cr", - "distort" => "e-distort", - - # Other flags & finishing - "progressive" => "pr", - "lossless" => "lo", - "color_profile" => "cp", - "colorProfile" => "cp", - "metadata" => "md", - "opacity" => "o", - "trim" => "t", - "zoom" => "z", - "page" => "pg", - - # Text overlay transformations - "font_size" => "fs", - "fontSize" => "fs", - "font_family" => "ff", - "fontFamily" => "ff", - "font_color" => "co", - "fontColor" => "co", - "inner_alignment" => "ia", - "innerAlignment" => "ia", - "padding" => "pa", - "alpha" => "al", - "typography" => "tg", - "line_height" => "lh", - "lineHeight" => "lh", - - # Overlay transformations - "layer_mode" => "lm", - "layerMode" => "lm", - - # Subtitles transformations - "font_outline" => "fol", - "fontOutline" => "fol", - "font_shadow" => "fsh", - "fontShadow" => "fsh", - "color" => "co", - - # Raw pass-through - "raw" => "raw" - }.freeze - - class << self - # Check if transformations should be added as query parameter - def add_as_query_parameter?(options) - options[:transformation_position] == QUERY_TRANSFORMATION_POSITION || - options["transformation_position"] == QUERY_TRANSFORMATION_POSITION || - options[:transformation_position] == "query" || - options["transformation_position"] == "query" - end - - # Get transformation key from supported transforms - def get_transform_key(transform) - return "" if transform.nil? || transform.to_s.empty? - - transform_str = transform.to_s - SUPPORTED_TRANSFORMS[transform_str] || - SUPPORTED_TRANSFORMS[transform_str.downcase] || - "" - end - - # Get chain transform delimiter - def get_chain_transform_delimiter - CHAIN_TRANSFORM_DELIMITER - end - - # Get transform delimiter - def get_transform_delimiter - TRANSFORM_DELIMITER - end - - # Get transform key-value delimiter - def get_transform_key_value_delimiter - TRANSFORM_KEY_VALUE_DELIMITER - end - - # Safe base64 encoding - def safe_btoa(str) - require("base64") - Base64.strict_encode64(str) - end - end - end -end diff --git a/lib/imagekitio/helpers/uuid_utils.rb b/lib/imagekitio/helpers/uuid_utils.rb deleted file mode 100644 index 6840505..0000000 --- a/lib/imagekitio/helpers/uuid_utils.rb +++ /dev/null @@ -1,18 +0,0 @@ -# frozen_string_literal: true - -require "securerandom" - -module Imagekitio - # @api private - # UUID utilities for ImageKit SDK - module UuidUtils - class << self - # Generates a UUID v4 string - # - # @return [String] A UUID v4 string - def uuid4 - SecureRandom.uuid - end - end - end -end diff --git a/lib/imagekitio/internal/transport/pooled_net_requester.rb b/lib/imagekitio/internal/transport/pooled_net_requester.rb index fa32384..dfed0d7 100644 --- a/lib/imagekitio/internal/transport/pooled_net_requester.rb +++ b/lib/imagekitio/internal/transport/pooled_net_requester.rb @@ -75,7 +75,7 @@ def build_request(request, &blk) case body in nil - nil + req["content-length"] ||= 0 unless req["transfer-encoding"] in String req["content-length"] ||= body.bytesize.to_s unless req["transfer-encoding"] req.body_stream = Imagekitio::Internal::Util::ReadIOAdapter.new(body, &blk) diff --git a/lib/imagekitio/internal/util.rb b/lib/imagekitio/internal/util.rb index 1dd7d34..6ca7b61 100644 --- a/lib/imagekitio/internal/util.rb +++ b/lib/imagekitio/internal/util.rb @@ -485,7 +485,7 @@ def writable_enum(&blk) end # @type [Regexp] - JSON_CONTENT = %r{^application/(?:vnd(?:\.[^.]+)*\+)?json(?!l)} + JSON_CONTENT = %r{^application/(?:[a-zA-Z0-9.-]+\+)?json(?!l)} # @type [Regexp] JSONL_CONTENT = %r{^application/(:?x-(?:n|l)djson)|(:?(?:x-)?jsonl)} diff --git a/lib/imagekitio/models/beta/v2/file_upload_params.rb b/lib/imagekitio/models/beta/v2/file_upload_params.rb index c348da3..adcadbd 100644 --- a/lib/imagekitio/models/beta/v2/file_upload_params.rb +++ b/lib/imagekitio/models/beta/v2/file_upload_params.rb @@ -9,68 +9,6 @@ class FileUploadParams < Imagekitio::Internal::Type::BaseModel extend Imagekitio::Internal::Type::RequestParameters::Converter include Imagekitio::Internal::Type::RequestParameters - # Serialize upload options to handle proper formatting for ImageKit backend API. - # Special cases handled: - # - tags: converted to comma-separated string - # - responseFields: converted to comma-separated string - # - extensions: JSON stringified - # - customMetadata: JSON stringified - # - transformation: JSON stringified - # - # @api private - # - # @param params [Object] - # - # @return [Array(Object, Hash{Symbol=>Object})] - def self.dump_request(params) - state = {can_retry: true} - case (dumped = dump(params, state: state)) - in Hash - serialized = serialize_upload_options(dumped) - options = Imagekitio::Internal::Util.coerce_hash!(serialized[:request_options]).to_h - request_options = state.fetch(:can_retry) ? options : {**options, max_retries: 0} - [serialized.except(:request_options), request_options] - else - [dumped, nil] - end - end - - # @api private - # - # @param upload_options [Hash{Symbol=>Object}] - # - # @return [Hash{Symbol=>Object}] - def self.serialize_upload_options(upload_options) - serialized = {} - - upload_options.each do |key, value| - # Skip nil values - if value.nil? - serialized[key] = value - next - end - - serialized[key] = case key - when :tags, :responseFields - # Tags and response fields should be comma-separated strings - value.is_a?(Array) ? value.join(",") : value - when :extensions - # Extensions should be JSON stringified - value.is_a?(Array) ? JSON.generate(value) : value - when :customMetadata - # Custom metadata should be JSON stringified - value.is_a?(Hash) ? JSON.generate(value) : value - when :transformation - # Transformation should be JSON stringified - value.is_a?(Hash) || value.respond_to?(:to_h) ? JSON.generate(value) : value - else - value - end - end - - serialized - end - # @!attribute file # The API accepts any of the following: # diff --git a/lib/imagekitio/models/file_upload_params.rb b/lib/imagekitio/models/file_upload_params.rb index b758651..e30764f 100644 --- a/lib/imagekitio/models/file_upload_params.rb +++ b/lib/imagekitio/models/file_upload_params.rb @@ -7,68 +7,6 @@ class FileUploadParams < Imagekitio::Internal::Type::BaseModel extend Imagekitio::Internal::Type::RequestParameters::Converter include Imagekitio::Internal::Type::RequestParameters - # Serialize upload options to handle proper formatting for ImageKit backend API. - # Special cases handled: - # - tags: converted to comma-separated string - # - responseFields: converted to comma-separated string - # - extensions: JSON stringified - # - customMetadata: JSON stringified - # - transformation: JSON stringified - # - # @api private - # - # @param params [Object] - # - # @return [Array(Object, Hash{Symbol=>Object})] - def self.dump_request(params) - state = {can_retry: true} - case (dumped = dump(params, state: state)) - in Hash - serialized = serialize_upload_options(dumped) - options = Imagekitio::Internal::Util.coerce_hash!(serialized[:request_options]).to_h - request_options = state.fetch(:can_retry) ? options : {**options, max_retries: 0} - [serialized.except(:request_options), request_options] - else - [dumped, nil] - end - end - - # @api private - # - # @param upload_options [Hash{Symbol=>Object}] - # - # @return [Hash{Symbol=>Object}] - def self.serialize_upload_options(upload_options) - serialized = {} - - upload_options.each do |key, value| - # Skip nil values - if value.nil? - serialized[key] = value - next - end - - serialized[key] = case key - when :tags, :responseFields - # Tags and response fields should be comma-separated strings - value.is_a?(Array) ? value.join(",") : value - when :extensions - # Extensions should be JSON stringified - value.is_a?(Array) ? JSON.generate(value) : value - when :customMetadata - # Custom metadata should be JSON stringified - value.is_a?(Hash) ? JSON.generate(value) : value - when :transformation - # Transformation should be JSON stringified - value.is_a?(Hash) || value.respond_to?(:to_h) ? JSON.generate(value) : value - else - value - end - end - - serialized - end - # @!attribute file # The API accepts any of the following: # diff --git a/rbi/imagekitio/client.rbi b/rbi/imagekitio/client.rbi index ad74d65..a5e5a64 100644 --- a/rbi/imagekitio/client.rbi +++ b/rbi/imagekitio/client.rbi @@ -47,9 +47,6 @@ module Imagekitio sig { returns(Imagekitio::Resources::Webhooks) } attr_reader :webhooks - sig { returns(Imagekitio::Helper) } - attr_reader :helper - # @api private sig { override.returns(T::Hash[String, String]) } private def auth_headers diff --git a/rbi/imagekitio/helpers/helper.rbi b/rbi/imagekitio/helpers/helper.rbi deleted file mode 100644 index f3babc7..0000000 --- a/rbi/imagekitio/helpers/helper.rbi +++ /dev/null @@ -1,41 +0,0 @@ -# typed: strong - -module Imagekitio - class Helper - sig { params(client: Imagekitio::Client).void } - def initialize(client:) - end - - # Builds a URL with transformations applied - sig { params(options: Imagekitio::Models::SrcOptions).returns(String) } - def build_url(options) - end - - # Generates transformation string from transformation objects - sig do - params( - transformations: T::Array[Imagekitio::Models::Transformation] - ).returns(String) - end - def build_transformation_string(transformations) - end - - # Generates authentication parameters for client-side file uploads - sig do - params(token: T.nilable(String), expire: T.nilable(Integer)).returns( - T::Hash[Symbol, T.any(String, Integer)] - ) - end - def get_authentication_parameters(token = nil, expire = nil) - end - - # Generates responsive image attributes for use in HTML tags - sig do - params(options: Imagekitio::Models::GetImageAttributesOptions).returns( - Imagekitio::Models::ResponsiveImageAttributes - ) - end - def get_responsive_image_attributes(options) - end - end -end diff --git a/rbi/imagekitio/internal/util.rbi b/rbi/imagekitio/internal/util.rbi index 9fbebf9..2feefe0 100644 --- a/rbi/imagekitio/internal/util.rbi +++ b/rbi/imagekitio/internal/util.rbi @@ -296,7 +296,7 @@ module Imagekitio end JSON_CONTENT = - T.let(%r{^application/(?:vnd(?:\.[^.]+)*\+)?json(?!l)}, Regexp) + T.let(%r{^application/(?:[a-zA-Z0-9.-]+\+)?json(?!l)}, Regexp) JSONL_CONTENT = T.let(%r{^application/(:?x-(?:n|l)djson)|(:?(?:x-)?jsonl)}, Regexp) 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 e0dc137..df8caf9 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" bundle exec rake test "$@" diff --git a/sig/imagekitio/client.rbs b/sig/imagekitio/client.rbs index 216a8c6..da497a4 100644 --- a/sig/imagekitio/client.rbs +++ b/sig/imagekitio/client.rbs @@ -30,8 +30,6 @@ module Imagekitio attr_reader webhooks: Imagekitio::Resources::Webhooks - attr_reader helper: Imagekitio::Helper - private def auth_headers: -> ::Hash[String, String] def base_url_overridden?: -> bool diff --git a/sig/imagekitio/helpers/helper.rbs b/sig/imagekitio/helpers/helper.rbs deleted file mode 100644 index 9756e66..0000000 --- a/sig/imagekitio/helpers/helper.rbs +++ /dev/null @@ -1,24 +0,0 @@ -module Imagekitio - class Helper - def initialize: (client: Imagekitio::Client) -> void - - # Builds a URL with transformations applied - def build_url: (Imagekitio::Models::SrcOptions options) -> String - - # Generates transformation string from transformation objects - def build_transformation_string: ( - Array[Imagekitio::Models::Transformation] transformations - ) -> String - - # Generates authentication parameters for client-side file uploads - def get_authentication_parameters: ( - ?String? token, - ?Integer? expire - ) -> Hash[Symbol, (String | Integer)] - - # Generates responsive image attributes for use in HTML tags - def get_responsive_image_attributes: ( - Imagekitio::Models::GetImageAttributesOptions options - ) -> Imagekitio::Models::ResponsiveImageAttributes - end -end diff --git a/sig/imagekitio/models/extensions.rbs b/sig/imagekitio/models/extensions.rbs index 2d382c3..0a4e156 100644 --- a/sig/imagekitio/models/extensions.rbs +++ b/sig/imagekitio/models/extensions.rbs @@ -1,11 +1,11 @@ module Imagekitio module Models type extension_item = - ExtensionItem::RemoveBg - | ExtensionItem::AIAutoDescription - | ExtensionItem::AITasks - | ExtensionItem::SavedExtension - | ExtensionItem::AutoTaggingExtension + Imagekitio::ExtensionItem::RemoveBg + | Imagekitio::ExtensionItem::AIAutoDescription + | Imagekitio::ExtensionItem::AITasks + | Imagekitio::ExtensionItem::SavedExtension + | Imagekitio::ExtensionItem::AutoTaggingExtension module ExtensionItem extend Imagekitio::Internal::Type::Union @@ -13,26 +13,26 @@ module Imagekitio type remove_bg = { name: :"remove-bg", - options: RemoveBg::Options + options: Imagekitio::ExtensionItem::RemoveBg::Options } class RemoveBg < Imagekitio::Internal::Type::BaseModel attr_accessor name: :"remove-bg" - attr_reader options: RemoveBg::Options? + attr_reader options: Imagekitio::ExtensionItem::RemoveBg::Options? def options=: ( - RemoveBg::Options - ) -> RemoveBg::Options + Imagekitio::ExtensionItem::RemoveBg::Options + ) -> Imagekitio::ExtensionItem::RemoveBg::Options def initialize: ( - ?options: RemoveBg::Options, + ?options: Imagekitio::ExtensionItem::RemoveBg::Options, ?name: :"remove-bg" ) -> void def to_hash: -> { name: :"remove-bg", - options: RemoveBg::Options + options: Imagekitio::ExtensionItem::RemoveBg::Options } type options = diff --git a/test/imagekitio/client_test.rb b/test/imagekitio/client_test.rb index c58cec4..617cd7e 100644 --- a/test/imagekitio/client_test.rb +++ b/test/imagekitio/client_test.rb @@ -276,7 +276,7 @@ def test_client_redirect_307 assert_requested(:any, "http://localhost/redirected", times: Imagekitio::Client::MAX_REDIRECTS) do assert_equal(recorded.method, _1.method) - # assert_equal(recorded.body, _1.body) skipping, since the request body is multipart encoded + assert_equal(recorded.body, _1.body) assert_equal( recorded.headers.transform_keys(&:downcase).fetch("content-type"), _1.headers.transform_keys(&:downcase).fetch("content-type") diff --git a/test/imagekitio/custom-tests/helper_authentication_test.rb b/test/imagekitio/custom-tests/helper_authentication_test.rb deleted file mode 100644 index 7acb32f..0000000 --- a/test/imagekitio/custom-tests/helper_authentication_test.rb +++ /dev/null @@ -1,116 +0,0 @@ -# frozen_string_literal: true - -require_relative "../test_helper" - -class HelperAuthenticationTest < Minitest::Test - def test_should_return_correct_authentication_parameters_with_provided_token_and_expire - private_key = "private_key_test" - client = Imagekitio::Client.new(private_key: private_key) - - token = "your_token" - expire = 1_582_269_249 - - params = client.helper.get_authentication_parameters(token: token, expire: expire) - - # Expected exact match with Node.js output - expected_signature = "e71bcd6031016b060d349d212e23e85c791decdd" - - assert_equal(token, params[:token]) - assert_equal(expire, params[:expire]) - assert_equal(expected_signature, params[:signature]) - end - - def test_should_return_authentication_parameters_with_required_properties_when_no_params_provided - private_key = "private_key_test" - client = Imagekitio::Client.new(private_key: private_key) - - params = client.helper.get_authentication_parameters - - # Check that all required properties exist - assert(params.key?(:token), "Expected token parameter") - assert(params.key?(:expire), "Expected expire parameter") - assert(params.key?(:signature), "Expected signature parameter") - - # Token should be a 32-character hex string - token = params[:token] - assert_instance_of(String, token) - assert_match(/^[0-9a-f]{32}$/, token, "Expected token to be 32-character hex format") - - # Expire should be a number greater than current time - expire = params[:expire] - assert_instance_of(Integer, expire) - current_time = Time.now.to_i - assert(expire > current_time, "Expected expire #{expire} to be greater than current time #{current_time}") - - # Signature should be a hex string (40 characters for HMAC-SHA1) - signature = params[:signature] - assert_instance_of(String, signature) - assert_match(/^[a-f0-9]{40}$/, signature, "Expected signature to be 40 character hex string") - end - - def test_should_handle_edge_case_with_expire_time_0 - private_key = "private_key_test" - client = Imagekitio::Client.new(private_key: private_key) - - token = "test-token" - expire = 0 - - params = client.helper.get_authentication_parameters(token: token, expire: expire) - - assert_equal(token, params[:token]) - - # When expire is 0 (falsy), it should use default expire time (30 minutes from now) - expire_result = params[:expire] - assert_instance_of(Integer, expire_result) - expected_expire = Time.now.to_i + (60 * 30) - # Allow a 10 second tolerance for test execution time - assert( - expire_result.between?(expected_expire - 10, expected_expire + 10), - "Expected expire to be close to #{expected_expire} (30 minutes from now), got #{expire_result}" - ) - - # Signature should be a hex string (40 characters for HMAC-SHA1) - signature = params[:signature] - assert_instance_of(String, signature) - assert_match(/^[a-f0-9]{40}$/, signature, "Expected signature to be 40 character hex string") - end - - def test_should_handle_empty_string_token - private_key = "private_key_test" - client = Imagekitio::Client.new(private_key: private_key) - - token = "" # Empty string is falsy - expire = 1_582_269_249 - - params = client.helper.get_authentication_parameters(token: token, expire: expire) - - # Since empty string is falsy, it should generate a token - token_result = params[:token] - assert_instance_of(String, token_result) - refute_empty(token_result, "Expected token to be generated when empty string is provided") - assert_match(/^[0-9a-f]{32}$/, token_result, "Expected generated token to be 32-character hex format") - - assert_equal(expire, params[:expire]) - - # Signature should be a hex string (40 characters for HMAC-SHA1) - signature = params[:signature] - assert_instance_of(String, signature) - assert_match(/^[a-f0-9]{40}$/, signature, "Expected signature to be 40 character hex string") - end - - def test_should_raise_error_when_private_key_is_not_provided - # Test with empty private key - assert_raises(ArgumentError, "Expected error when private key is empty") do - client = Imagekitio::Client.new(private_key: "") - client.helper.get_authentication_parameters(token: "test", expire: 123) - end - end - - def test_should_raise_error_when_private_key_is_nil - # Test with nil private key - assert_raises(ArgumentError, "Expected error when private key is nil") do - client = Imagekitio::Client.new(private_key: nil) - client.helper.get_authentication_parameters(token: "test", expire: 123) - end - end -end diff --git a/test/imagekitio/custom-tests/responsive_image_attributes_test.rb b/test/imagekitio/custom-tests/responsive_image_attributes_test.rb deleted file mode 100644 index 48fb059..0000000 --- a/test/imagekitio/custom-tests/responsive_image_attributes_test.rb +++ /dev/null @@ -1,306 +0,0 @@ -# frozen_string_literal: true - -require_relative "../test_helper" - -class ResponsiveImageAttributesTest < Minitest::Test - def setup - @client = Imagekitio::Client.new( - private_key: "private_key_test", - password: "test_password" - ) - end - - def test_bare_minimum_input - result = @client.helper.get_responsive_image_attributes( - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo" - ) - - # Expected object based on default device_breakpoints and image_breakpoints - expected = { - src: "https://ik.imagekit.io/demo/sample.jpg?tr=w-3840,c-at_max", - src_set: "https://ik.imagekit.io/demo/sample.jpg?tr=w-640,c-at_max 640w, https://ik.imagekit.io/demo/sample.jpg?tr=w-750,c-at_max 750w, https://ik.imagekit.io/demo/sample.jpg?tr=w-828,c-at_max 828w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1080,c-at_max 1080w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1200,c-at_max 1200w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1920,c-at_max 1920w, https://ik.imagekit.io/demo/sample.jpg?tr=w-2048,c-at_max 2048w, https://ik.imagekit.io/demo/sample.jpg?tr=w-3840,c-at_max 3840w", - sizes: "100vw", - width: nil - } - - assert_equal(expected, result.to_h) - end - - def test_sizes_provided_100vw - result = @client.helper.get_responsive_image_attributes( - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - sizes: "100vw" - ) - - # With a sizes value of "100vw", the function should use the same breakpoints as in the bare minimum case - expected = { - src: "https://ik.imagekit.io/demo/sample.jpg?tr=w-3840,c-at_max", - src_set: "https://ik.imagekit.io/demo/sample.jpg?tr=w-640,c-at_max 640w, https://ik.imagekit.io/demo/sample.jpg?tr=w-750,c-at_max 750w, https://ik.imagekit.io/demo/sample.jpg?tr=w-828,c-at_max 828w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1080,c-at_max 1080w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1200,c-at_max 1200w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1920,c-at_max 1920w, https://ik.imagekit.io/demo/sample.jpg?tr=w-2048,c-at_max 2048w, https://ik.imagekit.io/demo/sample.jpg?tr=w-3840,c-at_max 3840w", - sizes: "100vw", - width: nil - } - - assert_equal(expected, result.to_h) - end - - def test_width_only_dpr_strategy - result = @client.helper.get_responsive_image_attributes( - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - width: 400 - ) - - # When width is provided without sizes attribute, the DPR strategy should be used - expected = { - src: "https://ik.imagekit.io/demo/sample.jpg?tr=w-828,c-at_max", - src_set: "https://ik.imagekit.io/demo/sample.jpg?tr=w-640,c-at_max 1x, https://ik.imagekit.io/demo/sample.jpg?tr=w-828,c-at_max 2x", - sizes: nil, - width: 400.0 - } - - assert_equal(expected, result.to_h) - end - - def test_custom_breakpoints - result = @client.helper.get_responsive_image_attributes( - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - device_breakpoints: [200, 400, 800], - image_breakpoints: [100] - ) - - # For custom breakpoints, the breakpoints will be derived from the provided arrays - expected = { - src: "https://ik.imagekit.io/demo/sample.jpg?tr=w-800,c-at_max", - src_set: "https://ik.imagekit.io/demo/sample.jpg?tr=w-200,c-at_max 200w, https://ik.imagekit.io/demo/sample.jpg?tr=w-400,c-at_max 400w, https://ik.imagekit.io/demo/sample.jpg?tr=w-800,c-at_max 800w", - sizes: "100vw", - width: nil - } - - assert_equal(expected, result.to_h) - end - - def test_preserves_caller_transformations - result = @client.helper.get_responsive_image_attributes( - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - width: 500, - transformation: [Imagekitio::Models::Transformation.new(height: 300.0)] - ) - - # The provided transformation should be preserved in the output - expected = { - src: "https://ik.imagekit.io/demo/sample.jpg?tr=h-300:w-1080,c-at_max", - src_set: "https://ik.imagekit.io/demo/sample.jpg?tr=h-300:w-640,c-at_max 1x, https://ik.imagekit.io/demo/sample.jpg?tr=h-300:w-1080,c-at_max 2x", - sizes: nil, - width: 500.0 - } - - assert_equal(expected, result.to_h) - end - - def test_both_sizes_and_width_passed - result = @client.helper.get_responsive_image_attributes( - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - sizes: "50vw", - width: 600 - ) - - # Both sizes and width are provided, so the function should apply the sizes attribute while using width for DPR strategy - expected = { - src: "https://ik.imagekit.io/demo/sample.jpg?tr=w-3840,c-at_max", - src_set: "https://ik.imagekit.io/demo/sample.jpg?tr=w-384,c-at_max 384w, https://ik.imagekit.io/demo/sample.jpg?tr=w-640,c-at_max 640w, https://ik.imagekit.io/demo/sample.jpg?tr=w-750,c-at_max 750w, https://ik.imagekit.io/demo/sample.jpg?tr=w-828,c-at_max 828w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1080,c-at_max 1080w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1200,c-at_max 1200w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1920,c-at_max 1920w, https://ik.imagekit.io/demo/sample.jpg?tr=w-2048,c-at_max 2048w, https://ik.imagekit.io/demo/sample.jpg?tr=w-3840,c-at_max 3840w", - sizes: "50vw", - width: 600.0 - } - - assert_equal(expected, result.to_h) - end - - def test_multiple_transformations - result = @client.helper.get_responsive_image_attributes( - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - width: 450, - transformation: [ - Imagekitio::Models::Transformation.new(height: 300.0), - Imagekitio::Models::Transformation.new(ai_remove_background: true) - ] - ) - - # Multiple caller transformations should be combined appropriately - expected = { - src: "https://ik.imagekit.io/demo/sample.jpg?tr=h-300:e-bgremove:w-1080,c-at_max", - src_set: "https://ik.imagekit.io/demo/sample.jpg?tr=h-300:e-bgremove:w-640,c-at_max 1x, https://ik.imagekit.io/demo/sample.jpg?tr=h-300:e-bgremove:w-1080,c-at_max 2x", - sizes: nil, - width: 450.0 - } - - assert_equal(expected, result.to_h) - end - - def test_sizes_causes_breakpoint_pruning_33vw_path - result = @client.helper.get_responsive_image_attributes( - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - sizes: "(min-width: 800px) 33vw, 100vw" - ) - - # When specified with a sizes attribute that prunes breakpoints, the output should reflect the pruned values - expected = { - src: "https://ik.imagekit.io/demo/sample.jpg?tr=w-3840,c-at_max", - src_set: "https://ik.imagekit.io/demo/sample.jpg?tr=w-256,c-at_max 256w, https://ik.imagekit.io/demo/sample.jpg?tr=w-384,c-at_max 384w, https://ik.imagekit.io/demo/sample.jpg?tr=w-640,c-at_max 640w, https://ik.imagekit.io/demo/sample.jpg?tr=w-750,c-at_max 750w, https://ik.imagekit.io/demo/sample.jpg?tr=w-828,c-at_max 828w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1080,c-at_max 1080w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1200,c-at_max 1200w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1920,c-at_max 1920w, https://ik.imagekit.io/demo/sample.jpg?tr=w-2048,c-at_max 2048w, https://ik.imagekit.io/demo/sample.jpg?tr=w-3840,c-at_max 3840w", - sizes: "(min-width: 800px) 33vw, 100vw", - width: nil - } - - assert_equal(expected, result.to_h) - end - - def test_using_query_parameters_and_transformation_position - result = @client.helper.get_responsive_image_attributes( - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - width: 450, - transformation: [ - Imagekitio::Models::Transformation.new(height: 300), - Imagekitio::Models::Transformation.new(ai_remove_background: true) - ], - query_parameters: {key: "value"}, - transformation_position: :path - ) - - # The function should respect the transformation position and query parameters - expected = { - src: "https://ik.imagekit.io/demo/tr:h-300:e-bgremove:w-1080,c-at_max/sample.jpg?key=value", - src_set: "https://ik.imagekit.io/demo/tr:h-300:e-bgremove:w-640,c-at_max/sample.jpg?key=value 1x, https://ik.imagekit.io/demo/tr:h-300:e-bgremove:w-1080,c-at_max/sample.jpg?key=value 2x", - sizes: nil, - width: 450.0 - } - - assert_equal(expected, result.to_h) - end - - # Hash-based API test - verify that plain hashes work for responsive image attributes - def test_should_work_with_plain_hashes_for_responsive_image_attributes - # Using plain hashes instead of model objects - result = @client.helper.get_responsive_image_attributes( - { - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - width: 450, - transformation: [ - { - height: 300 - }, - { - ai_remove_background: true - } - ] - } - ) - - # Multiple caller transformations should be combined appropriately - expected = { - src: "https://ik.imagekit.io/demo/sample.jpg?tr=h-300:e-bgremove:w-1080,c-at_max", - src_set: "https://ik.imagekit.io/demo/sample.jpg?tr=h-300:e-bgremove:w-640,c-at_max 1x, https://ik.imagekit.io/demo/sample.jpg?tr=h-300:e-bgremove:w-1080,c-at_max 2x", - sizes: nil, - width: 450 - } - - assert_equal(expected, result.to_h) - end - - # Test to verify that srcset uses integer descriptors (640w) not float (640.0w) - # This tests both model object and hash approaches - def test_should_use_integer_descriptors_in_srcset_with_model_object - # Using GetImageAttributesOptions model with Float array (as defined in schema) - result = @client.helper.get_responsive_image_attributes( - Imagekitio::Models::GetImageAttributesOptions.new( - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - device_breakpoints: [320.0, 640.0, 1280.0], # SDK converts to floats - image_breakpoints: [] - ) - ) - - src_set = result.src_set - - # Should have integer descriptors like "320w", NOT "320.0w" - assert_includes(src_set, "320w") - assert_includes(src_set, "640w") - assert_includes(src_set, "1280w") - - # Should NOT have float descriptors - refute_includes(src_set, "320.0w") - refute_includes(src_set, "640.0w") - refute_includes(src_set, "1280.0w") - end - - def test_should_use_integer_descriptors_in_srcset_with_hash - # Using plain hash with integer breakpoints - result = @client.helper.get_responsive_image_attributes( - { - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - device_breakpoints: [320, 640, 1280], - image_breakpoints: [] - } - ) - - src_set = result.src_set - - # Should have integer descriptors like "320w", NOT "320.0w" - assert_includes(src_set, "320w") - assert_includes(src_set, "640w") - assert_includes(src_set, "1280w") - - # Should NOT have float descriptors - refute_includes(src_set, "320.0w") - refute_includes(src_set, "640.0w") - refute_includes(src_set, "1280.0w") - end - - def test_fallback_when_no_usable_vw_tokens - result = @client.helper.get_responsive_image_attributes( - src: "sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - sizes: "100%" - ) - - # When sizes has no vw tokens, all breakpoints should be used - expected = { - src: "https://ik.imagekit.io/demo/sample.jpg?tr=w-3840,c-at_max", - src_set: "https://ik.imagekit.io/demo/sample.jpg?tr=w-16,c-at_max 16w, https://ik.imagekit.io/demo/sample.jpg?tr=w-32,c-at_max 32w, https://ik.imagekit.io/demo/sample.jpg?tr=w-48,c-at_max 48w, https://ik.imagekit.io/demo/sample.jpg?tr=w-64,c-at_max 64w, https://ik.imagekit.io/demo/sample.jpg?tr=w-96,c-at_max 96w, https://ik.imagekit.io/demo/sample.jpg?tr=w-128,c-at_max 128w, https://ik.imagekit.io/demo/sample.jpg?tr=w-256,c-at_max 256w, https://ik.imagekit.io/demo/sample.jpg?tr=w-384,c-at_max 384w, https://ik.imagekit.io/demo/sample.jpg?tr=w-640,c-at_max 640w, https://ik.imagekit.io/demo/sample.jpg?tr=w-750,c-at_max 750w, https://ik.imagekit.io/demo/sample.jpg?tr=w-828,c-at_max 828w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1080,c-at_max 1080w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1200,c-at_max 1200w, https://ik.imagekit.io/demo/sample.jpg?tr=w-1920,c-at_max 1920w, https://ik.imagekit.io/demo/sample.jpg?tr=w-2048,c-at_max 2048w, https://ik.imagekit.io/demo/sample.jpg?tr=w-3840,c-at_max 3840w", - sizes: "100%", - width: nil - } - - assert_equal(expected, result.to_h) - end - - # Test to verify signed URLs work correctly in responsive image attributes - def test_should_generate_signed_urls_in_srcset - result = @client.helper.get_responsive_image_attributes( - { - src: "sdk-testing-files/future-search.png", - url_endpoint: "https://ik.imagekit.io/demo", - device_breakpoints: [640, 1280], - image_breakpoints: [], - signed: true - } - ) - - expected = { - src: "https://ik.imagekit.io/demo/sdk-testing-files/future-search.png?tr=w-1280,c-at_max&ik-s=cce0258e8b27bee5d4b642bcee996c5fac11a907", - src_set: "https://ik.imagekit.io/demo/sdk-testing-files/future-search.png?tr=w-640,c-at_max&ik-s=d326eadc97c62b0896dc1bb872355a47c8b71943 640w, https://ik.imagekit.io/demo/sdk-testing-files/future-search.png?tr=w-1280,c-at_max&ik-s=cce0258e8b27bee5d4b642bcee996c5fac11a907 1280w", - sizes: "100vw", - width: nil - } - - assert_equal(expected, result.to_h) - end -end diff --git a/test/imagekitio/custom-tests/url-generation/advanced_url_generation_test.rb b/test/imagekitio/custom-tests/url-generation/advanced_url_generation_test.rb deleted file mode 100644 index aa8298a..0000000 --- a/test/imagekitio/custom-tests/url-generation/advanced_url_generation_test.rb +++ /dev/null @@ -1,501 +0,0 @@ -# frozen_string_literal: true - -require_relative "../../test_helper" - -class AdvancedURLGenerationTest < Minitest::Test - def setup - @client = Imagekitio::Client.new( - private_key: "My Private API Key" - ) - end - - # AI Transformation Tests - def test_should_generate_the_correct_url_for_ai_background_removal_when_set_to_true - transformation = [ - Imagekitio::Models::Transformation.new( - ai_remove_background: true - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=e-bgremove" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_for_external_ai_background_removal_when_set_to_true - transformation = [ - Imagekitio::Models::Transformation.new( - ai_remove_background_external: true - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=e-removedotbg" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_when_ai_drop_shadow_transformation_is_set_to_true - transformation = [ - Imagekitio::Models::Transformation.new( - ai_drop_shadow: true - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=e-dropshadow" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_when_gradient_transformation_is_set_to_true - transformation = [ - Imagekitio::Models::Transformation.new( - gradient: true - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=e-gradient" - assert_equal(expected, url) - end - - def test_should_not_apply_ai_background_removal_when_value_is_not_true - transformation = [ - Imagekitio::Models::Transformation.new - # AIRemoveBackground: false, # This would be the case for false values - - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg" - assert_equal(expected, url) - end - - def test_should_not_apply_external_ai_background_removal_when_value_is_not_true - transformation = [ - Imagekitio::Models::Transformation.new - # AIRemoveBackgroundExternal: false, # This would be the case for false values - - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg" - assert_equal(expected, url) - end - - def test_should_handle_ai_transformations_with_parameters - transformation = [ - Imagekitio::Models::Transformation.new( - ai_drop_shadow: "custom-shadow-params" - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=e-dropshadow-custom-shadow-params" - assert_equal(expected, url) - end - - def test_should_handle_gradient_with_parameters - transformation = [ - Imagekitio::Models::Transformation.new( - gradient: "ld-top_from-green_to-00FF0010_sp-1" - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=e-gradient-ld-top_from-green_to-00FF0010_sp-1" - assert_equal(expected, url) - end - - def test_should_combine_ai_transformations_with_regular_transformations - transformation = [ - Imagekitio::Models::Transformation.new( - width: 300.0, - height: 200.0, - ai_remove_background: true - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=w-300,h-200,e-bgremove" - assert_equal(expected, url) - end - - def test_should_handle_multiple_ai_transformations - transformation = [ - Imagekitio::Models::Transformation.new( - ai_remove_background: true, - ai_drop_shadow: true - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=e-bgremove,e-dropshadow" - assert_equal(expected, url) - end - - # Parameter-specific tests - def test_should_generate_the_correct_url_for_width_transformation_when_provided_with_a_number_value - transformation = [ - Imagekitio::Models::Transformation.new( - width: 400.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=w-400" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_for_height_transformation_when_provided_with_a_string_value - transformation = [ - Imagekitio::Models::Transformation.new( - height: "300" - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=h-300" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_for_aspect_ratio_transformation_when_provided_with_colon_format - transformation = [ - Imagekitio::Models::Transformation.new( - aspect_ratio: "4:3" - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=ar-4:3" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_for_quality_transformation_when_provided_with_a_number_value - transformation = [ - Imagekitio::Models::Transformation.new( - quality: 80.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=q-80" - assert_equal(expected, url) - end - - # Additional parameter validation tests from Node.js SDK - def test_should_skip_transformation_parameters_that_are_undefined_or_empty - transformation = [ - Imagekitio::Models::Transformation.new( - width: 300.0 - # Quality is not set - should be ignored - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=w-300" - assert_equal(expected, url) - end - - def test_should_handle_boolean_transformation_values - transformation = [ - Imagekitio::Models::Transformation.new( - trim: true - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=t-true" - assert_equal(expected, url) - end - - def test_should_handle_transformation_parameter_with_empty_string_value - transformation = [ - Imagekitio::Models::Transformation.new( - default_image: "" - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg" - assert_equal(expected, url) - end - - def test_should_handle_complex_transformation_combinations - transformation = [ - Imagekitio::Models::Transformation.new( - width: 300.0, - height: 200.0, - quality: 85.0, - border: "5_FF0000" - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=w-300,h-200,q-85,b-5_FF0000" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_with_many_transformations_including_video_and_ai_transforms - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0, - aspect_ratio: "4-3", - quality: 40.0, - crop: :force, - crop_mode: :extract, - focus: "left", - format_: :jpeg, - radius: 50.0, - background: "A94D34", - border: "5-A94D34", - rotation: 90.0, - blur: 10.0, - named: "some_name", - progressive: true, - lossless: true, - trim: 5.0, - metadata: true, - color_profile: true, - default_image: "/folder/file.jpg/", - dpr: 3.0, - x: 10.0, - y_: 20.0, - x_center: 30.0, - y_center: 40.0, - flip: :h, - opacity: 0.8, - zoom: 2.0, - # Video transformations - video_codec: :h264, - audio_codec: :aac, - start_offset: 5.0, - end_offset: 15.0, - duration: 10.0, - streaming_resolutions: [:"1440", :"1080"], - # AI transformations - grayscale: true, - ai_upscale: true, - ai_retouch: true, - ai_variation: true, - ai_drop_shadow: true, - ai_change_background: "prompt-car", - ai_edit: "prompt-make it vintage", - ai_remove_background: true, - contrast_stretch: true, - shadow: "bl-15_st-40_x-10_y-N5", - sharpen: 10.0, - unsharp_mask: "2-2-0.8-0.024", - gradient: "from-red_to-white", - # New transformations - color_replace: "FF0000_50_0000FF", - distort: "p-100_50_200_150_300_250_400_350", - original: true, - page: "2_4", - raw: "h-200,w-300,l-image,i-logo.png,l-end" - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path.jpg?tr=h-300,w-400,ar-4-3,q-40,c-force,cm-extract,fo-left,f-jpeg,r-50,bg-A94D34,b-5-A94D34,rt-90,bl-10,n-some_name,pr-true,lo-true,t-5,md-true,cp-true,di-folder@@file.jpg,dpr-3,x-10,y-20,xc-30,yc-40,fl-h,o-0.8,z-2,vc-h264,ac-aac,so-5,eo-15,du-10,sr-1440_1080,e-grayscale,e-upscale,e-retouch,e-genvar,e-dropshadow,e-changebg-prompt-car,e-edit-prompt-make it vintage,e-bgremove,e-contrast,e-shadow-bl-15_st-40_x-10_y-N5,e-sharpen-10,e-usm-2-2-0.8-0.024,e-gradient-from-red_to-white,cr-FF0000_50_0000FF,e-distort-p-100_50_200_150_300_250_400_350,orig-true,pg-2_4,h-200,w-300,l-image,i-logo.png,l-end" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_for_radius_with_string_value - transformation = [ - Imagekitio::Models::Transformation.new( - radius: "10_20_30_40" - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=r-10_20_30_40" - assert_equal(expected, url) - end - - # Hash-based API test - verify that plain hashes work for both transformations and options - # Developers can use hashes instead of model objects for a more concise, Ruby-idiomatic syntax - def test_should_work_with_plain_hashes_for_transformations_and_options - # Using plain hashes instead of Transformation.new and SrcOptions.new - url = @client.helper.build_url( - { - src: "/test_path1.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: [ - { - width: 300, - height: 200, - quality: 85, - border: "5_FF0000", - ai_remove_background: true, - ai_drop_shadow: true - } - ] - } - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path1.jpg?tr=w-300,h-200,q-85,b-5_FF0000,e-bgremove,e-dropshadow" - assert_equal(expected, url) - end -end diff --git a/test/imagekitio/custom-tests/url-generation/basic_url_generation_test.rb b/test/imagekitio/custom-tests/url-generation/basic_url_generation_test.rb deleted file mode 100644 index e414575..0000000 --- a/test/imagekitio/custom-tests/url-generation/basic_url_generation_test.rb +++ /dev/null @@ -1,409 +0,0 @@ -# frozen_string_literal: true - -require_relative "../../test_helper" - -class BasicURLGenerationTest < Minitest::Test - def setup - @client = Imagekitio::Client.new( - private_key: "My Private API Key" - ) - end - - def test_should_return_an_empty_string_when_src_is_not_provided - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query - ) - ) - - assert_equal("", url) - end - - def test_should_generate_a_valid_url_when_src_is_slash - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint" - assert_equal(expected, url) - end - - def test_should_generate_a_valid_url_when_src_is_provided_with_transformation - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path.jpg" - assert_equal(expected, url) - end - - def test_should_generate_a_valid_url_when_a_src_is_provided_without_transformation - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "https://ik.imagekit.io/test_url_endpoint/test_path_alt.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path_alt.jpg" - assert_equal(expected, url) - end - - def test_should_generate_a_valid_url_when_undefined_transformation_parameters_are_provided_with_path - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path_alt.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path_alt.jpg" - assert_equal(expected, url) - end - - def test_by_default_transformation_position_should_be_query - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0 - ), - Imagekitio::Models::Transformation.new( - rotation: 90.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path.jpg?tr=h-300,w-400:rt-90" - assert_equal(expected, url) - end - - def test_should_generate_the_url_without_sdk_version - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation: transformation, - transformation_position: :path - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:h-300,w-400/test_path.jpg" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_with_a_valid_src_and_transformation - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path.jpg?tr=h-300,w-400" - assert_equal(expected, url) - end - - def test_should_add_transformation_as_query_when_src_has_absolute_url_even_if_transformation_position_is_path - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "https://my.custom.domain.com/test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://my.custom.domain.com/test_path.jpg?tr=h-300,w-400" - assert_equal(expected, url) - end - - def test_should_generate_correct_url_when_src_has_query_params - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "https://ik.imagekit.io/imagekit_id/new-endpoint/test_path.jpg?t1=v1", - url_endpoint: "https://ik.imagekit.io/imagekit_id/new-endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/imagekit_id/new-endpoint/test_path.jpg?t1=v1&tr=h-300,w-400" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_when_the_provided_path_contains_multiple_leading_slashes - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "///test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path.jpg?tr=h-300,w-400" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_when_the_url_endpoint_is_overridden - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint_alt", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint_alt/test_path.jpg?tr=h-300,w-400" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_with_transformation_position_as_query_parameter_when_src_is_provided - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path.jpg?tr=h-300,w-400" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_with_a_valid_src_parameter_and_transformation - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "https://ik.imagekit.io/test_url_endpoint/test_path_alt.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path_alt.jpg?tr=h-300,w-400" - assert_equal(expected, url) - end - - def test_should_merge_query_parameters_correctly_in_the_generated_url - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0 - ) - ] - - query_parameters = { - t2: "v2", - t3: "v3" - } - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "https://ik.imagekit.io/test_url_endpoint/test_path_alt.jpg?t1=v1", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - query_parameters: query_parameters, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path_alt.jpg?t1=v1&t2=v2&t3=v3&tr=h-300,w-400" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_with_chained_transformations - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0 - ), - Imagekitio::Models::Transformation.new( - rotation: 90.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path.jpg?tr=h-300,w-400:rt-90" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_with_chained_transformations_including_raw_transformation - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0 - ), - Imagekitio::Models::Transformation.new( - raw: "rndm_trnsf-abcd" - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path.jpg?tr=h-300,w-400:rndm_trnsf-abcd" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_when_border_transformation_is_applied - transformation = [ - Imagekitio::Models::Transformation.new( - height: 300.0, - width: 400.0, - border: "20_FF0000" - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path.jpg?tr=h-300,w-400,b-20_FF0000" - assert_equal(expected, url) - end - - def test_should_generate_the_correct_url_when_transformation_has_empty_key_and_value - transformation = [ - Imagekitio::Models::Transformation.new( - raw: "" - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/test_path.jpg" - assert_equal(expected, url) - end - - def test_should_generate_a_valid_url_when_cname_is_used - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://custom.domain.com", - transformation_position: :query - ) - ) - - expected = "https://custom.domain.com/test_path.jpg" - assert_equal(expected, url) - end - - def test_should_generate_a_valid_url_when_cname_with_path_is_used - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/test_path.jpg", - url_endpoint: "https://custom.domain.com/url-pattern", - transformation_position: :query - ) - ) - - expected = "https://custom.domain.com/url-pattern/test_path.jpg" - assert_equal(expected, url) - end -end diff --git a/test/imagekitio/custom-tests/url-generation/build_transformation_string_test.rb b/test/imagekitio/custom-tests/url-generation/build_transformation_string_test.rb deleted file mode 100644 index d4726b4..0000000 --- a/test/imagekitio/custom-tests/url-generation/build_transformation_string_test.rb +++ /dev/null @@ -1,132 +0,0 @@ -# frozen_string_literal: true - -require_relative "../../test_helper" - -class BuildTransformationStringTest < Minitest::Test - def setup - @client = Imagekitio::Client.new( - private_key: "test-key" - ) - end - - def test_should_return_empty_string_for_empty_transformation_array - result = @client.helper.build_transformation_string(nil) - assert_equal("", result) - - result = @client.helper.build_transformation_string([]) - assert_equal("", result) - end - - def test_should_generate_transformation_string_for_width_only - transformation = [ - Imagekitio::Models::Transformation.new( - width: 300.0 - ) - ] - - result = @client.helper.build_transformation_string(transformation) - expected = "w-300" - assert_equal(expected, result) - end - - def test_should_generate_transformation_string_for_multiple_parameters - transformation = [ - Imagekitio::Models::Transformation.new( - width: 300.0, - height: 200.0 - ) - ] - - result = @client.helper.build_transformation_string(transformation) - expected = "w-300,h-200" - assert_equal(expected, result) - end - - def test_should_generate_transformation_string_for_chained_transformations - transformation = [ - Imagekitio::Models::Transformation.new( - width: 300.0 - ), - Imagekitio::Models::Transformation.new( - height: 200.0 - ) - ] - - result = @client.helper.build_transformation_string(transformation) - expected = "w-300:h-200" - assert_equal(expected, result) - end - - def test_should_handle_empty_transformation_object - transformation = [ - Imagekitio::Models::Transformation.new - ] - - result = @client.helper.build_transformation_string(transformation) - expected = "" - assert_equal(expected, result) - end - - def test_should_handle_transformation_with_overlay - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "Hello" - ) - ) - ] - - result = @client.helper.build_transformation_string(transformation) - expected = "l-text,i-Hello,l-end" - assert_equal(expected, result) - end - - def test_should_handle_raw_transformation_parameter - transformation = [ - Imagekitio::Models::Transformation.new( - raw: "custom-transform-123" - ) - ] - - result = @client.helper.build_transformation_string(transformation) - expected = "custom-transform-123" - assert_equal(expected, result) - end - - def test_should_handle_mixed_parameters_with_raw - transformation = [ - Imagekitio::Models::Transformation.new( - width: 300.0, - raw: "custom-param-123" - ) - ] - - result = @client.helper.build_transformation_string(transformation) - expected = "w-300,custom-param-123" - assert_equal(expected, result) - end - - def test_should_handle_quality_parameter - transformation = [ - Imagekitio::Models::Transformation.new( - quality: 80.0 - ) - ] - - result = @client.helper.build_transformation_string(transformation) - expected = "q-80" - assert_equal(expected, result) - end - - def test_should_handle_aspect_ratio_parameter - transformation = [ - Imagekitio::Models::Transformation.new( - aspect_ratio: "4:3" - ) - ] - - result = @client.helper.build_transformation_string(transformation) - expected = "ar-4:3" - assert_equal(expected, result) - end -end diff --git a/test/imagekitio/custom-tests/url-generation/overlay_test.rb b/test/imagekitio/custom-tests/url-generation/overlay_test.rb deleted file mode 100644 index 3094aed..0000000 --- a/test/imagekitio/custom-tests/url-generation/overlay_test.rb +++ /dev/null @@ -1,859 +0,0 @@ -# frozen_string_literal: true - -require_relative "../../test_helper" - -class OverlayTest < Minitest::Test - def setup - @client = Imagekitio::Client.new( - private_key: "My Private API Key" - ) - end - - # Basic overlay tests - def test_should_ignore_overlay_when_type_property_is_missing - transformation = [ - Imagekitio::Models::Transformation.new( - width: 300.0 - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:w-300/base-image.jpg" - assert_equal(expected, url) - end - - def test_should_ignore_text_overlay_when_text_property_is_missing - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/base-image.jpg" - assert_equal(expected, url) - end - - def test_should_ignore_image_overlay_when_input_property_is_missing - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::ImageOverlay.new( - input: "" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/base-image.jpg" - assert_equal(expected, url) - end - - def test_should_ignore_video_overlay_when_input_property_is_missing - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::VideoOverlay.new( - input: "" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/base-image.jpg" - assert_equal(expected, url) - end - - def test_should_ignore_subtitle_overlay_when_input_property_is_missing - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::SubtitleOverlay.new( - input: "" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/base-image.jpg" - assert_equal(expected, url) - end - - def test_should_ignore_solid_color_overlay_when_color_property_is_missing - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::SolidColorOverlay.new( - color: "" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/base-image.jpg" - assert_equal(expected, url) - end - - # Basic overlay functionality tests - def test_should_generate_url_with_text_overlay_using_url_encoding - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "Minimal Text" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:l-text,i-Minimal%20Text,l-end/base-image.jpg" - assert_equal(expected, url) - end - - def test_should_generate_url_with_image_overlay_from_input_file - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::ImageOverlay.new( - input: "logo.png" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:l-image,i-logo.png,l-end/base-image.jpg" - assert_equal(expected, url) - end - - def test_should_generate_url_with_video_overlay_from_input_file - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::VideoOverlay.new( - input: "play-pause-loop.mp4" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-video.mp4", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:l-video,i-play-pause-loop.mp4,l-end/base-video.mp4" - assert_equal(expected, url) - end - - def test_should_generate_url_with_subtitle_overlay_from_input_file - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::SubtitleOverlay.new( - input: "subtitle.srt" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-video.mp4", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:l-subtitles,i-subtitle.srt,l-end/base-video.mp4" - assert_equal(expected, url) - end - - def test_should_generate_url_with_solid_color_overlay_using_background_color - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::SolidColorOverlay.new( - color: "FF0000" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:l-image,i-ik_canvas,bg-FF0000,l-end/base-image.jpg" - assert_equal(expected, url) - end - - def test_should_generate_url_with_multiple_complex_overlays_including_nested_transformations - transformation = [ - # Text overlay - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "Every thing", - position: Imagekitio::Models::OverlayPosition.new( - x: "10", - y_: "20", - focus: :center - ), - timing: Imagekitio::Models::OverlayTiming.new( - start: 5.0, - duration: "10", - end_: 15.0 - ), - transformation: [ - Imagekitio::Models::TextOverlayTransformation.new( - width: "bw_mul_0.5", - font_size: 20.0, - font_family: "Arial", - font_color: "0000ff", - inner_alignment: :left, - padding: 5.0, - alpha: 7.0, - typography: "b", - background: "red", - radius: 10.0, - rotation: "N45", - flip: :h, - line_height: 20.0 - ) - ] - ) - ), - # Image overlay - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::ImageOverlay.new( - input: "logo.png", - position: Imagekitio::Models::OverlayPosition.new( - x: "10", - y_: "20", - focus: :center - ), - timing: Imagekitio::Models::OverlayTiming.new( - start: 5.0, - duration: "10", - end_: 15.0 - ), - transformation: [ - Imagekitio::Models::Transformation.new( - width: "bw_mul_0.5", - height: "bh_mul_0.5", - rotation: "N45", - flip: :h, - overlay: Imagekitio::Models::TextOverlay.new( - text: "Nested text overlay" - ) - ) - ] - ) - ), - # Video overlay - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::VideoOverlay.new( - input: "play-pause-loop.mp4", - position: Imagekitio::Models::OverlayPosition.new( - x: "10", - y_: "20", - focus: :center - ), - timing: Imagekitio::Models::OverlayTiming.new( - start: 5.0, - duration: "10", - end_: 15.0 - ), - transformation: [ - Imagekitio::Models::Transformation.new( - width: "bw_mul_0.5", - height: "bh_mul_0.5", - rotation: "N45", - flip: :h - ) - ] - ) - ), - # Subtitle overlay - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::SubtitleOverlay.new( - input: "subtitle.srt", - position: Imagekitio::Models::OverlayPosition.new( - x: "10", - y_: "20", - focus: :center - ), - timing: Imagekitio::Models::OverlayTiming.new( - start: 5.0, - duration: "10", - end_: 15.0 - ), - transformation: [ - Imagekitio::Models::SubtitleOverlayTransformation.new( - background: "red", - color: "0000ff", - font_family: "Arial", - font_outline: "2_A1CCDD50", - font_shadow: "A1CCDD_3" - ) - ] - ) - ), - # Solid color overlay - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::SolidColorOverlay.new( - color: "FF0000", - position: Imagekitio::Models::OverlayPosition.new( - x: "10", - y_: "20", - focus: :center - ), - timing: Imagekitio::Models::OverlayTiming.new( - start: 5.0, - duration: "10", - end_: 15.0 - ), - transformation: [ - Imagekitio::Models::SolidColorOverlayTransformation.new( - width: "bw_mul_0.5", - height: "bh_mul_0.5", - alpha: 0.5, - background: "red", - gradient: true, - radius: :max - ) - ] - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:l-text,i-Every%20thing,lx-10,ly-20,lfo-center,lso-5,leo-15,ldu-10,w-bw_mul_0.5,fs-20,ff-Arial,co-0000ff,ia-left,pa-5,al-7,tg-b,bg-red,r-10,rt-N45,fl-h,lh-20,l-end:l-image,i-logo.png,lx-10,ly-20,lfo-center,lso-5,leo-15,ldu-10,w-bw_mul_0.5,h-bh_mul_0.5,rt-N45,fl-h,l-text,i-Nested%20text%20overlay,l-end,l-end:l-video,i-play-pause-loop.mp4,lx-10,ly-20,lfo-center,lso-5,leo-15,ldu-10,w-bw_mul_0.5,h-bh_mul_0.5,rt-N45,fl-h,l-end:l-subtitles,i-subtitle.srt,lx-10,ly-20,lfo-center,lso-5,leo-15,ldu-10,bg-red,co-0000ff,ff-Arial,fol-2_A1CCDD50,fsh-A1CCDD_3,l-end:l-image,i-ik_canvas,bg-FF0000,lx-10,ly-20,lfo-center,lso-5,leo-15,ldu-10,w-bw_mul_0.5,h-bh_mul_0.5,al-0.5,bg-red,e-gradient,r-max,l-end/base-image.jpg" - assert_equal(expected, url) - end - - # Overlay encoding tests - def test_should_use_plain_encoding_for_simple_image_paths_with_slashes_converted_to_double_at - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::ImageOverlay.new( - input: "/customer_logo/nykaa.png" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/medium_cafe_B1iTdD0C.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-image,i-customer_logo@@nykaa.png,l-end/medium_cafe_B1iTdD0C.jpg" - assert_equal(expected, url) - end - - def test_should_use_base64_encoding_for_image_paths_containing_special_characters - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::ImageOverlay.new( - input: "/customer_logo/Ñykaa.png" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/medium_cafe_B1iTdD0C.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-image,ie-Y3VzdG9tZXJfbG9nby%2FDkXlrYWEucG5n,l-end/medium_cafe_B1iTdD0C.jpg" - assert_equal(expected, url) - end - - def test_should_use_plain_encoding_for_simple_text_overlays - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "Manu" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/medium_cafe_B1iTdD0C.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-text,i-Manu,l-end/medium_cafe_B1iTdD0C.jpg" - assert_equal(expected, url) - end - - def test_should_convert_slashes_to_double_at_in_font_family_paths_for_custom_fonts - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "Manu", - transformation: [ - Imagekitio::Models::TextOverlayTransformation.new( - font_family: "nested-path/Poppins-Regular_Q15GrYWmL.ttf" - ) - ] - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/medium_cafe_B1iTdD0C.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-text,i-Manu,ff-nested-path@@Poppins-Regular_Q15GrYWmL.ttf,l-end/medium_cafe_B1iTdD0C.jpg" - assert_equal(expected, url) - end - - def test_should_use_url_encoding_for_text_overlays_with_spaces_and_safe_characters - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "alnum123-._ " - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/medium_cafe_B1iTdD0C.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-text,i-alnum123-._%20,l-end/medium_cafe_B1iTdD0C.jpg" - assert_equal(expected, url) - end - - def test_should_use_base64_encoding_for_text_overlays_with_special_unicode_characters - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "Let's use ©, ®, ™, etc" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/medium_cafe_B1iTdD0C.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-text,ie-TGV0J3MgdXNlIMKpLCDCriwg4oSiLCBldGM%3D,l-end/medium_cafe_B1iTdD0C.jpg" - assert_equal(expected, url) - end - - def test_should_use_plain_encoding_when_explicitly_specified_for_text_overlay - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "HelloWorld", - encoding: :plain - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-text,i-HelloWorld,l-end/sample.jpg" - assert_equal(expected, url) - end - - def test_should_use_base64_encoding_when_explicitly_specified_for_text_overlay - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "HelloWorld", - encoding: :base64 - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-text,ie-SGVsbG9Xb3JsZA%3D%3D,l-end/sample.jpg" - assert_equal(expected, url) - end - - def test_should_use_plain_encoding_when_explicitly_specified_for_image_overlay - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::ImageOverlay.new( - input: "/customer/logo.png", - encoding: :plain - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-image,i-customer@@logo.png,l-end/sample.jpg" - assert_equal(expected, url) - end - - def test_should_use_base64_encoding_when_explicitly_specified_for_image_overlay - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::ImageOverlay.new( - input: "/customer/logo.png", - encoding: :base64 - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-image,ie-Y3VzdG9tZXIvbG9nby5wbmc%3D,l-end/sample.jpg" - assert_equal(expected, url) - end - - def test_should_use_base64_encoding_when_explicitly_specified_for_video_overlay - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::VideoOverlay.new( - input: "/path/to/video.mp4", - encoding: :base64 - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/sample.mp4", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-video,ie-cGF0aC90by92aWRlby5tcDQ%3D,l-end/sample.mp4" - assert_equal(expected, url) - end - - def test_should_use_plain_encoding_when_explicitly_specified_for_subtitle_overlay - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::SubtitleOverlay.new( - input: "/sub.srt", - encoding: :plain - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/sample.mp4", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-subtitles,i-sub.srt,l-end/sample.mp4" - assert_equal(expected, url) - end - - def test_should_use_base64_encoding_when_explicitly_specified_for_subtitle_overlay - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::SubtitleOverlay.new( - input: "sub.srt", - encoding: :base64 - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/sample.mp4", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-subtitles,ie-c3ViLnNydA%3D%3D,l-end/sample.mp4" - assert_equal(expected, url) - end - - def test_should_properly_encode_overlay_text_when_transformations_are_in_query_parameters - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "Minimal Text" - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/sample.jpg", - url_endpoint: "https://ik.imagekit.io/demo", - transformation_position: :query, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/demo/sample.jpg?tr=l-text,i-Minimal%20Text,l-end" - assert_equal(expected, url) - end - - # Layer mode tests - def test_should_generate_url_with_image_overlay_and_multiply_layer_mode - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::ImageOverlay.new( - input: "overlay.png", - layer_mode: :multiply - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:l-image,i-overlay.png,lm-multiply,l-end/base-image.jpg" - assert_equal(expected, url) - end - - def test_should_generate_url_with_image_overlay_and_displace_layer_mode - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::ImageOverlay.new( - input: "displacement-map.png", - layer_mode: :displace, - position: Imagekitio::Models::OverlayPosition.new( - x: "10", - y_: "20" - ) - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:l-image,i-displacement-map.png,lm-displace,lx-10,ly-20,l-end/base-image.jpg" - assert_equal(expected, url) - end - - def test_should_generate_url_with_image_overlay_and_cutout_layer_mode - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::ImageOverlay.new( - input: "mask.png", - layer_mode: :cutout - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:l-image,i-mask.png,lm-cutout,l-end/base-image.jpg" - assert_equal(expected, url) - end - - def test_should_generate_url_with_image_overlay_and_cutter_layer_mode - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::ImageOverlay.new( - input: "shape.png", - layer_mode: :cutter - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: transformation - ) - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:l-image,i-shape.png,lm-cutter,l-end/base-image.jpg" - assert_equal(expected, url) - end - - # Hash-based API test - verify that plain hashes work for overlays - def test_should_work_with_plain_hashes_for_text_overlay - # Using plain hashes for everything including overlay - url = @client.helper.build_url( - { - src: "/base-image.jpg", - url_endpoint: "https://ik.imagekit.io/test_url_endpoint", - transformation_position: :path, - transformation: [ - { - width: 300, - height: 200, - overlay: { - type: :text, - text: "Hello World", - position: { - x: "10", - y_: "20", - focus: :center - }, - transformation: [ - { - font_size: 20, - font_color: "FF0000" - } - ] - } - } - ] - } - ) - - expected = "https://ik.imagekit.io/test_url_endpoint/tr:w-300,h-200,l-text,i-Hello%20World,lx-10,ly-20,lfo-center,fs-20,co-FF0000,l-end/base-image.jpg" - assert_equal(expected, url) - end -end diff --git a/test/imagekitio/custom-tests/url-generation/signing_test.rb b/test/imagekitio/custom-tests/url-generation/signing_test.rb deleted file mode 100644 index 70c4863..0000000 --- a/test/imagekitio/custom-tests/url-generation/signing_test.rb +++ /dev/null @@ -1,235 +0,0 @@ -# frozen_string_literal: true - -require_relative "../../test_helper" - -class SigningTest < Minitest::Test - def setup - @client = Imagekitio::Client.new( - private_key: "dummy-key" - ) - end - - def test_should_generate_a_signed_url_when_signed_is_true_without_expires_in - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "sdk-testing-files/future-search.png", - url_endpoint: "https://ik.imagekit.io/demo/", - signed: true - ) - ) - - expected = "https://ik.imagekit.io/demo/sdk-testing-files/future-search.png?ik-s=32dbbbfc5f945c0403c71b54c38e76896ef2d6b0" - assert_equal(expected, url) - end - - def test_should_generate_a_signed_url_when_signed_is_true_with_expires_in - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "sdk-testing-files/future-search.png", - url_endpoint: "https://ik.imagekit.io/demo/", - signed: true, - expires_in: 3600.0 - ) - ) - - # Expect ik-t exist in the URL. We don't assert signature because it will keep changing. - assert_includes(url, "ik-t") - end - - def test_should_generate_a_signed_url_when_expires_in_is_above_0_and_even_if_signed_is_false - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "sdk-testing-files/future-search.png", - url_endpoint: "https://ik.imagekit.io/demo/", - signed: false, - expires_in: 3600.0 - ) - ) - - # Expect ik-t exist in the URL. We don't assert signature because it will keep changing. - assert_includes(url, "ik-t") - end - - def test_should_generate_signed_url_with_special_characters_in_filename - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "sdk-testing-files/हिन्दी.png", - url_endpoint: "https://ik.imagekit.io/demo/", - signed: true - ) - ) - - expected = "https://ik.imagekit.io/demo/sdk-testing-files/%E0%A4%B9%E0%A4%BF%E0%A4%A8%E0%A5%8D%E0%A4%A6%E0%A5%80.png?ik-s=3fff2f31da1f45e007adcdbe95f88c8c330e743c" - assert_equal(expected, url) - end - - def test_should_generate_signed_url_with_text_overlay_containing_special_characters - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "हिन्दी", - transformation: [ - Imagekitio::Models::TextOverlayTransformation.new( - font_color: "red", - font_size: "32", - font_family: "sdk-testing-files/Poppins-Regular_Q15GrYWmL.ttf" - ) - ] - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "sdk-testing-files/हिन्दी.png", - url_endpoint: "https://ik.imagekit.io/demo/", - transformation: transformation, - signed: true - ) - ) - - expected = "https://ik.imagekit.io/demo/sdk-testing-files/%E0%A4%B9%E0%A4%BF%E0%A4%A8%E0%A5%8D%E0%A4%A6%E0%A5%80.png?tr=l-text,ie-4KS54KS%2F4KSo4KWN4KSm4KWA,co-red,fs-32,ff-sdk-testing-files@@Poppins-Regular_Q15GrYWmL.ttf,l-end&ik-s=ac9f24a03080102555e492185533c1ae6bd93fa7" - assert_equal(expected, url) - end - - def test_should_generate_signed_url_with_text_overlay_and_special_characters_using_path_transformation_position - transformation = [ - Imagekitio::Models::Transformation.new( - overlay: Imagekitio::Models::TextOverlay.new( - text: "हिन्दी", - transformation: [ - Imagekitio::Models::TextOverlayTransformation.new( - font_color: "red", - font_size: "32", - font_family: "sdk-testing-files/Poppins-Regular_Q15GrYWmL.ttf" - ) - ] - ) - ) - ] - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "sdk-testing-files/हिन्दी.png", - url_endpoint: "https://ik.imagekit.io/demo/", - transformation_position: :path, - transformation: transformation, - signed: true - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:l-text,ie-4KS54KS%2F4KSo4KWN4KSm4KWA,co-red,fs-32,ff-sdk-testing-files@@Poppins-Regular_Q15GrYWmL.ttf,l-end/sdk-testing-files/%E0%A4%B9%E0%A4%BF%E0%A4%A8%E0%A5%8D%E0%A4%A6%E0%A5%80.png?ik-s=69f2ecbb7364bbbad24616e1f7f1bac5a560fc71" - assert_equal(expected, url) - end - - def test_should_generate_signed_url_with_query_parameters - query_params = { - "version" => "1.0", - "cache" => "false" - } - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "sdk-testing-files/future-search.png", - url_endpoint: "https://ik.imagekit.io/demo/", - query_parameters: query_params, - signed: true - ) - ) - - expected = "https://ik.imagekit.io/demo/sdk-testing-files/future-search.png?version=1.0&cache=false&ik-s=f2e5a1b8b6a0b03fd63789dfc6413a94acef9fd8" - assert_equal(expected, url) - end - - def test_should_generate_signed_url_with_transformations_and_query_parameters - transformation = [ - Imagekitio::Models::Transformation.new( - width: 300.0, - height: 200.0 - ) - ] - - query_params = { - "version" => "2.0" - } - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "sdk-testing-files/future-search.png", - url_endpoint: "https://ik.imagekit.io/demo/", - transformation: transformation, - query_parameters: query_params, - signed: true - ) - ) - - expected = "https://ik.imagekit.io/demo/sdk-testing-files/future-search.png?version=2.0&tr=w-300,h-200&ik-s=601d97a7834b7554f4dabf0d3fc3a219ceeb6b31" - assert_equal(expected, url) - end - - def test_should_not_sign_url_when_signed_is_false - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "sdk-testing-files/future-search.png", - url_endpoint: "https://ik.imagekit.io/demo/", - signed: false - ) - ) - - expected = "https://ik.imagekit.io/demo/sdk-testing-files/future-search.png" - assert_equal(expected, url) - refute_includes(url, "ik-s=") - refute_includes(url, "ik-t=") - end - - def test_should_generate_signed_url_with_transformations_in_path_position_and_query_parameters - transformation = [ - Imagekitio::Models::Transformation.new( - width: 300.0, - height: 200.0 - ) - ] - - query_params = { - "version" => "2.0" - } - - url = @client.helper.build_url( - Imagekitio::Models::SrcOptions.new( - src: "sdk-testing-files/future-search.png", - url_endpoint: "https://ik.imagekit.io/demo/", - transformation: transformation, - transformation_position: :path, - query_parameters: query_params, - signed: true - ) - ) - - expected = "https://ik.imagekit.io/demo/tr:w-300,h-200/sdk-testing-files/future-search.png?version=2.0&ik-s=dd1ee8f83d019bc59fd57a5fc4674a11eb8a3496" - assert_equal(expected, url) - end - - # Hash-based API test - verify that plain hashes work for signed URLs - def test_should_work_with_plain_hashes_for_signed_url_with_transformations - # Using plain hashes instead of model objects - url = @client.helper.build_url( - { - src: "sdk-testing-files/future-search.png", - url_endpoint: "https://ik.imagekit.io/demo/", - transformation: [ - { - width: 300, - height: 200 - } - ], - query_parameters: { - "version" => "2.0" - }, - signed: true - } - ) - - expected = "https://ik.imagekit.io/demo/sdk-testing-files/future-search.png?version=2.0&tr=w-300,h-200&ik-s=601d97a7834b7554f4dabf0d3fc3a219ceeb6b31" - assert_equal(expected, url) - end -end diff --git a/test/imagekitio/internal/util_test.rb b/test/imagekitio/internal/util_test.rb index 976d5b0..1b29975 100644 --- a/test/imagekitio/internal/util_test.rb +++ b/test/imagekitio/internal/util_test.rb @@ -171,6 +171,8 @@ def test_json_content cases = { "application/json" => true, "application/jsonl" => false, + "application/arbitrary+json" => true, + "application/ARBITRARY+json" => true, "application/vnd.github.v3+json" => true, "application/vnd.api+json" => true } diff --git a/test/imagekitio/resources/accounts/origins_test.rb b/test/imagekitio/resources/accounts/origins_test.rb index 49f7a48..78285d1 100644 --- a/test/imagekitio/resources/accounts/origins_test.rb +++ b/test/imagekitio/resources/accounts/origins_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::Accounts::OriginsTest < Imagekitio::Test::ResourceTest def test_create_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.accounts.origins.create( @@ -114,7 +114,7 @@ def test_create_required_params end def test_update_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.accounts.origins.update( @@ -225,7 +225,7 @@ def test_update_required_params end def test_list - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.accounts.origins.list @@ -235,7 +235,7 @@ def test_list end def test_delete - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.accounts.origins.delete("id") @@ -245,7 +245,7 @@ def test_delete end def test_get - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.accounts.origins.get("id") diff --git a/test/imagekitio/resources/accounts/url_endpoints_test.rb b/test/imagekitio/resources/accounts/url_endpoints_test.rb index fa91264..966e30b 100644 --- a/test/imagekitio/resources/accounts/url_endpoints_test.rb +++ b/test/imagekitio/resources/accounts/url_endpoints_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::Accounts::URLEndpointsTest < Imagekitio::Test::ResourceTest def test_create_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.accounts.url_endpoints.create(description: "My custom URL endpoint") @@ -24,7 +24,7 @@ def test_create_required_params end def test_update_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.accounts.url_endpoints.update("id", description: "My custom URL endpoint") @@ -44,7 +44,7 @@ def test_update_required_params end def test_list - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.accounts.url_endpoints.list @@ -54,7 +54,7 @@ def test_list end def test_delete - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.accounts.url_endpoints.delete("id") @@ -64,7 +64,7 @@ def test_delete end def test_get - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.accounts.url_endpoints.get("id") diff --git a/test/imagekitio/resources/accounts/usage_test.rb b/test/imagekitio/resources/accounts/usage_test.rb index f928f45..64346dd 100644 --- a/test/imagekitio/resources/accounts/usage_test.rb +++ b/test/imagekitio/resources/accounts/usage_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::Accounts::UsageTest < Imagekitio::Test::ResourceTest def test_get_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.accounts.usage.get(end_date: "2019-12-27", start_date: "2019-12-27") diff --git a/test/imagekitio/resources/assets_test.rb b/test/imagekitio/resources/assets_test.rb index f4b2148..882e51f 100644 --- a/test/imagekitio/resources/assets_test.rb +++ b/test/imagekitio/resources/assets_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::AssetsTest < Imagekitio::Test::ResourceTest def test_list - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.assets.list diff --git a/test/imagekitio/resources/beta/v2/files_test.rb b/test/imagekitio/resources/beta/v2/files_test.rb index 640bff4..c2f5728 100644 --- a/test/imagekitio/resources/beta/v2/files_test.rb +++ b/test/imagekitio/resources/beta/v2/files_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::Beta::V2::FilesTest < Imagekitio::Test::ResourceTest def test_upload_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.beta.v2.files.upload(file: Pathname(__FILE__), file_name: "fileName") diff --git a/test/imagekitio/resources/cache/invalidation_test.rb b/test/imagekitio/resources/cache/invalidation_test.rb index 2d29a04..dec4bfc 100644 --- a/test/imagekitio/resources/cache/invalidation_test.rb +++ b/test/imagekitio/resources/cache/invalidation_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::Cache::InvalidationTest < Imagekitio::Test::ResourceTest def test_create_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.cache.invalidation.create(url: "https://ik.imagekit.io/your_imagekit_id/default-image.jpg") @@ -21,7 +21,7 @@ def test_create_required_params end def test_get - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.cache.invalidation.get("requestId") diff --git a/test/imagekitio/resources/custom_metadata_fields_test.rb b/test/imagekitio/resources/custom_metadata_fields_test.rb index fcddba8..1d455ad 100644 --- a/test/imagekitio/resources/custom_metadata_fields_test.rb +++ b/test/imagekitio/resources/custom_metadata_fields_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::CustomMetadataFieldsTest < Imagekitio::Test::ResourceTest def test_create_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.custom_metadata_fields.create(label: "price", name: "price", schema: {type: :Number}) @@ -24,7 +24,7 @@ def test_create_required_params end def test_update - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.custom_metadata_fields.update("id") @@ -43,7 +43,7 @@ def test_update end def test_list - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.custom_metadata_fields.list @@ -53,7 +53,7 @@ def test_list end def test_delete - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.custom_metadata_fields.delete("id") diff --git a/test/imagekitio/resources/files/bulk_test.rb b/test/imagekitio/resources/files/bulk_test.rb index 56991d8..6699988 100644 --- a/test/imagekitio/resources/files/bulk_test.rb +++ b/test/imagekitio/resources/files/bulk_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::Files::BulkTest < Imagekitio::Test::ResourceTest def test_delete_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.bulk.delete(file_ids: %w[598821f949c0a938d57563bd 598821f949c0a938d57563be]) @@ -21,7 +21,7 @@ def test_delete_required_params end def test_add_tags_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.bulk.add_tags( @@ -41,7 +41,7 @@ def test_add_tags_required_params end def test_remove_ai_tags_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.bulk.remove_ai_tags( @@ -61,7 +61,7 @@ def test_remove_ai_tags_required_params end def test_remove_tags_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.bulk.remove_tags( diff --git a/test/imagekitio/resources/files/metadata_test.rb b/test/imagekitio/resources/files/metadata_test.rb index ce2626c..2c48eb2 100644 --- a/test/imagekitio/resources/files/metadata_test.rb +++ b/test/imagekitio/resources/files/metadata_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::Files::MetadataTest < Imagekitio::Test::ResourceTest def test_get - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.metadata.get("fileId") @@ -33,7 +33,7 @@ def test_get end def test_get_from_url_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.metadata.get_from_url(url: "https://example.com") diff --git a/test/imagekitio/resources/files/versions_test.rb b/test/imagekitio/resources/files/versions_test.rb index b1d3dc4..3abf45a 100644 --- a/test/imagekitio/resources/files/versions_test.rb +++ b/test/imagekitio/resources/files/versions_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::Files::VersionsTest < Imagekitio::Test::ResourceTest def test_list - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.versions.list("fileId") @@ -14,7 +14,7 @@ def test_list end def test_delete_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.versions.delete("versionId", file_id: "fileId") @@ -30,7 +30,7 @@ def test_delete_required_params end def test_get_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.versions.get("versionId", file_id: "fileId") @@ -73,7 +73,7 @@ def test_get_required_params end def test_restore_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.versions.restore("versionId", file_id: "fileId") diff --git a/test/imagekitio/resources/files_test.rb b/test/imagekitio/resources/files_test.rb index 314183f..aedd4b4 100644 --- a/test/imagekitio/resources/files_test.rb +++ b/test/imagekitio/resources/files_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::FilesTest < Imagekitio::Test::ResourceTest def test_update - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.update("fileId") @@ -14,7 +14,7 @@ def test_update end def test_delete - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.delete("fileId") @@ -24,7 +24,7 @@ def test_delete end def test_copy_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.copy(destination_path: "/folder/to/copy/into/", source_file_path: "/path/to/file.jpg") @@ -41,7 +41,7 @@ def test_copy_required_params end def test_get - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.get("fileId") @@ -84,7 +84,7 @@ def test_get end def test_move_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.move(destination_path: "/folder/to/move/into/", source_file_path: "/path/to/file.jpg") @@ -101,7 +101,7 @@ def test_move_required_params end def test_rename_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.rename(file_path: "/path/to/file.jpg", new_file_name: "newFileName.jpg") @@ -117,7 +117,7 @@ def test_rename_required_params end def test_upload_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.files.upload(file: Pathname(__FILE__), file_name: "fileName") diff --git a/test/imagekitio/resources/folders/job_test.rb b/test/imagekitio/resources/folders/job_test.rb index 810a3c2..02f4606 100644 --- a/test/imagekitio/resources/folders/job_test.rb +++ b/test/imagekitio/resources/folders/job_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::Folders::JobTest < Imagekitio::Test::ResourceTest def test_get - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.folders.job.get("jobId") diff --git a/test/imagekitio/resources/folders_test.rb b/test/imagekitio/resources/folders_test.rb index eb4097a..ec2ee28 100644 --- a/test/imagekitio/resources/folders_test.rb +++ b/test/imagekitio/resources/folders_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::FoldersTest < Imagekitio::Test::ResourceTest def test_create_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.folders.create(folder_name: "summer", parent_folder_path: "/product/images/") @@ -20,7 +20,7 @@ def test_create_required_params end def test_delete_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.folders.delete(folder_path: "/folder/to/delete/") @@ -36,7 +36,7 @@ def test_delete_required_params end def test_copy_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.folders.copy( @@ -56,7 +56,7 @@ def test_copy_required_params end def test_move_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.folders.move( @@ -76,7 +76,7 @@ def test_move_required_params end def test_rename_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.folders.rename(folder_path: "/path/of/folder", new_folder_name: "new-folder-name") diff --git a/test/imagekitio/resources/saved_extensions_test.rb b/test/imagekitio/resources/saved_extensions_test.rb index 9ce1a47..9102206 100644 --- a/test/imagekitio/resources/saved_extensions_test.rb +++ b/test/imagekitio/resources/saved_extensions_test.rb @@ -4,7 +4,7 @@ class Imagekitio::Test::Resources::SavedExtensionsTest < Imagekitio::Test::ResourceTest def test_create_required_params - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.saved_extensions.create( @@ -30,7 +30,7 @@ def test_create_required_params end def test_update - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.saved_extensions.update("id") @@ -51,7 +51,7 @@ def test_update end def test_list - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.saved_extensions.list @@ -61,7 +61,7 @@ def test_list end def test_delete - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.saved_extensions.delete("id") @@ -71,7 +71,7 @@ def test_delete end def test_get - skip("Prism tests are disabled") + skip("Mock server tests are disabled") response = @image_kit.saved_extensions.get("id")