imagekitio 3.0.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.ignore +2 -0
- data/CHANGELOG.md +116 -0
- data/README.md +538 -679
- data/SECURITY.md +27 -0
- data/lib/imagekitio/client.rb +122 -195
- data/lib/imagekitio/errors.rb +226 -2
- data/lib/imagekitio/file_part.rb +58 -0
- data/lib/imagekitio/helpers/crypto_utils.rb +25 -0
- data/lib/imagekitio/helpers/helper.rb +689 -0
- data/lib/imagekitio/helpers/transformation_utils.rb +164 -0
- data/lib/imagekitio/helpers/uuid_utils.rb +18 -0
- data/lib/imagekitio/internal/transport/base_client.rb +567 -0
- data/lib/imagekitio/internal/transport/pooled_net_requester.rb +217 -0
- data/lib/imagekitio/internal/type/array_of.rb +168 -0
- data/lib/imagekitio/internal/type/base_model.rb +530 -0
- data/lib/imagekitio/internal/type/base_page.rb +55 -0
- data/lib/imagekitio/internal/type/boolean.rb +77 -0
- data/lib/imagekitio/internal/type/converter.rb +327 -0
- data/lib/imagekitio/internal/type/enum.rb +156 -0
- data/lib/imagekitio/internal/type/file_input.rb +111 -0
- data/lib/imagekitio/internal/type/hash_of.rb +188 -0
- data/lib/imagekitio/internal/type/request_parameters.rb +42 -0
- data/lib/imagekitio/internal/type/union.rb +250 -0
- data/lib/imagekitio/internal/type/unknown.rb +81 -0
- data/lib/imagekitio/internal/util.rb +915 -0
- data/lib/imagekitio/internal.rb +20 -0
- data/lib/imagekitio/models/accounts/origin_create_params.rb +24 -0
- data/lib/imagekitio/models/accounts/origin_delete_params.rb +16 -0
- data/lib/imagekitio/models/accounts/origin_get_params.rb +16 -0
- data/lib/imagekitio/models/accounts/origin_list_params.rb +16 -0
- data/lib/imagekitio/models/accounts/origin_list_response.rb +11 -0
- data/lib/imagekitio/models/accounts/origin_request.rb +547 -0
- data/lib/imagekitio/models/accounts/origin_response.rb +568 -0
- data/lib/imagekitio/models/accounts/origin_update_params.rb +24 -0
- data/lib/imagekitio/models/accounts/url_endpoint_create_params.rb +16 -0
- data/lib/imagekitio/models/accounts/url_endpoint_delete_params.rb +16 -0
- data/lib/imagekitio/models/accounts/url_endpoint_get_params.rb +16 -0
- data/lib/imagekitio/models/accounts/url_endpoint_list_params.rb +16 -0
- data/lib/imagekitio/models/accounts/url_endpoint_list_response.rb +11 -0
- data/lib/imagekitio/models/accounts/url_endpoint_request.rb +110 -0
- data/lib/imagekitio/models/accounts/url_endpoint_response.rb +123 -0
- data/lib/imagekitio/models/accounts/url_endpoint_update_params.rb +16 -0
- data/lib/imagekitio/models/accounts/usage_get_params.rb +37 -0
- data/lib/imagekitio/models/accounts/usage_get_response.rb +51 -0
- data/lib/imagekitio/models/asset_list_params.rb +158 -0
- data/lib/imagekitio/models/asset_list_response.rb +24 -0
- data/lib/imagekitio/models/base_overlay.rb +21 -0
- data/lib/imagekitio/models/base_webhook_event.rb +24 -0
- data/lib/imagekitio/models/beta/v2/file_upload_params.rb +510 -0
- data/lib/imagekitio/models/beta/v2/file_upload_response.rb +618 -0
- data/lib/imagekitio/models/cache/invalidation_create_params.rb +27 -0
- data/lib/imagekitio/models/cache/invalidation_create_response.rb +23 -0
- data/lib/imagekitio/models/cache/invalidation_get_params.rb +16 -0
- data/lib/imagekitio/models/cache/invalidation_get_response.rb +35 -0
- data/lib/imagekitio/models/custom_metadata_field.rb +243 -0
- data/lib/imagekitio/models/custom_metadata_field_create_params.rb +238 -0
- data/lib/imagekitio/models/custom_metadata_field_delete_params.rb +14 -0
- data/lib/imagekitio/models/custom_metadata_field_delete_response.rb +10 -0
- data/lib/imagekitio/models/custom_metadata_field_list_params.rb +36 -0
- data/lib/imagekitio/models/custom_metadata_field_list_response.rb +9 -0
- data/lib/imagekitio/models/custom_metadata_field_update_params.rb +212 -0
- data/lib/imagekitio/models/extensions.rb +136 -0
- data/lib/imagekitio/models/file.rb +497 -0
- data/lib/imagekitio/models/file_copy_params.rb +43 -0
- data/lib/imagekitio/models/file_copy_response.rb +10 -0
- data/lib/imagekitio/models/file_delete_params.rb +14 -0
- data/lib/imagekitio/models/file_get_params.rb +14 -0
- data/lib/imagekitio/models/file_move_params.rb +33 -0
- data/lib/imagekitio/models/file_move_response.rb +10 -0
- data/lib/imagekitio/models/file_rename_params.rb +61 -0
- data/lib/imagekitio/models/file_rename_response.rb +21 -0
- data/lib/imagekitio/models/file_update_params.rb +22 -0
- data/lib/imagekitio/models/file_update_response.rb +104 -0
- data/lib/imagekitio/models/file_upload_params.rb +540 -0
- data/lib/imagekitio/models/file_upload_response.rb +611 -0
- data/lib/imagekitio/models/files/bulk_add_tags_params.rb +35 -0
- data/lib/imagekitio/models/files/bulk_add_tags_response.rb +24 -0
- data/lib/imagekitio/models/files/bulk_delete_params.rb +27 -0
- data/lib/imagekitio/models/files/bulk_delete_response.rb +24 -0
- data/lib/imagekitio/models/files/bulk_remove_ai_tags_params.rb +35 -0
- data/lib/imagekitio/models/files/bulk_remove_ai_tags_response.rb +24 -0
- data/lib/imagekitio/models/files/bulk_remove_tags_params.rb +35 -0
- data/lib/imagekitio/models/files/bulk_remove_tags_response.rb +24 -0
- data/lib/imagekitio/models/files/metadata_get_from_url_params.rb +28 -0
- data/lib/imagekitio/models/files/metadata_get_params.rb +16 -0
- data/lib/imagekitio/models/files/version_delete_params.rb +22 -0
- data/lib/imagekitio/models/files/version_delete_response.rb +12 -0
- data/lib/imagekitio/models/files/version_get_params.rb +22 -0
- data/lib/imagekitio/models/files/version_list_params.rb +16 -0
- data/lib/imagekitio/models/files/version_list_response.rb +10 -0
- data/lib/imagekitio/models/files/version_restore_params.rb +22 -0
- data/lib/imagekitio/models/folder.rb +76 -0
- data/lib/imagekitio/models/folder_copy_params.rb +44 -0
- data/lib/imagekitio/models/folder_copy_response.rb +23 -0
- data/lib/imagekitio/models/folder_create_params.rb +43 -0
- data/lib/imagekitio/models/folder_create_response.rb +10 -0
- data/lib/imagekitio/models/folder_delete_params.rb +25 -0
- data/lib/imagekitio/models/folder_delete_response.rb +10 -0
- data/lib/imagekitio/models/folder_move_params.rb +34 -0
- data/lib/imagekitio/models/folder_move_response.rb +23 -0
- data/lib/imagekitio/models/folder_rename_params.rb +59 -0
- data/lib/imagekitio/models/folder_rename_response.rb +23 -0
- data/lib/imagekitio/models/folders/job_get_params.rb +16 -0
- data/lib/imagekitio/models/folders/job_get_response.rb +74 -0
- data/lib/imagekitio/models/get_image_attributes_options.rb +68 -0
- data/lib/imagekitio/models/image_overlay.rb +66 -0
- data/lib/imagekitio/models/metadata.rb +483 -0
- data/lib/imagekitio/models/overlay.rb +28 -0
- data/lib/imagekitio/models/overlay_position.rb +101 -0
- data/lib/imagekitio/models/overlay_timing.rb +97 -0
- data/lib/imagekitio/models/responsive_image_attributes.rb +48 -0
- data/lib/imagekitio/models/solid_color_overlay.rb +42 -0
- data/lib/imagekitio/models/solid_color_overlay_transformation.rb +135 -0
- data/lib/imagekitio/models/src_options.rb +96 -0
- data/lib/imagekitio/models/streaming_resolution.rb +22 -0
- data/lib/imagekitio/models/subtitle_overlay.rb +64 -0
- data/lib/imagekitio/models/subtitle_overlay_transformation.rb +113 -0
- data/lib/imagekitio/models/text_overlay.rb +65 -0
- data/lib/imagekitio/models/text_overlay_transformation.rb +267 -0
- data/lib/imagekitio/models/transformation.rb +1100 -0
- data/lib/imagekitio/models/transformation_position.rb +19 -0
- data/lib/imagekitio/models/unsafe_unwrap_webhook_event.rb +36 -0
- data/lib/imagekitio/models/unwrap_webhook_event.rb +36 -0
- data/lib/imagekitio/models/update_file_request.rb +164 -0
- data/lib/imagekitio/models/upload_post_transform_error_event.rb +180 -0
- data/lib/imagekitio/models/upload_post_transform_success_event.rb +143 -0
- data/lib/imagekitio/models/upload_pre_transform_error_event.rb +108 -0
- data/lib/imagekitio/models/upload_pre_transform_success_event.rb +690 -0
- data/lib/imagekitio/models/video_overlay.rb +64 -0
- data/lib/imagekitio/models/video_transformation_accepted_event.rb +279 -0
- data/lib/imagekitio/models/video_transformation_error_event.rb +326 -0
- data/lib/imagekitio/models/video_transformation_ready_event.rb +379 -0
- data/lib/imagekitio/models/webhook_unsafe_unwrap_params.rb +14 -0
- data/lib/imagekitio/models/webhook_unwrap_params.rb +14 -0
- data/lib/imagekitio/models.rb +160 -0
- data/lib/imagekitio/request_options.rb +77 -0
- data/lib/imagekitio/resources/accounts/origins.rb +145 -0
- data/lib/imagekitio/resources/accounts/url_endpoints.rb +151 -0
- data/lib/imagekitio/resources/accounts/usage.rb +46 -0
- data/lib/imagekitio/resources/accounts.rb +26 -0
- data/lib/imagekitio/resources/assets.rb +54 -0
- data/lib/imagekitio/resources/beta/v2/files.rb +110 -0
- data/lib/imagekitio/resources/beta/v2.rb +20 -0
- data/lib/imagekitio/resources/beta.rb +18 -0
- data/lib/imagekitio/resources/cache/invalidation.rb +66 -0
- data/lib/imagekitio/resources/cache.rb +18 -0
- data/lib/imagekitio/resources/custom_metadata_fields.rb +133 -0
- data/lib/imagekitio/resources/files/bulk.rb +131 -0
- data/lib/imagekitio/resources/files/metadata.rb +69 -0
- data/lib/imagekitio/resources/files/versions.rb +132 -0
- data/lib/imagekitio/resources/files.rb +305 -0
- data/lib/imagekitio/resources/folders/job.rb +39 -0
- data/lib/imagekitio/resources/folders.rb +166 -0
- data/lib/imagekitio/resources/webhooks.rb +30 -0
- data/lib/imagekitio/version.rb +5 -0
- data/lib/imagekitio.rb +181 -13
- data/manifest.yaml +15 -0
- data/rbi/imagekitio/client.rbi +92 -0
- data/rbi/imagekitio/errors.rbi +205 -0
- data/rbi/imagekitio/file_part.rbi +37 -0
- data/rbi/imagekitio/helpers/helper.rbi +41 -0
- data/rbi/imagekitio/internal/transport/base_client.rbi +295 -0
- data/rbi/imagekitio/internal/transport/pooled_net_requester.rbi +80 -0
- data/rbi/imagekitio/internal/type/array_of.rbi +104 -0
- data/rbi/imagekitio/internal/type/base_model.rbi +304 -0
- data/rbi/imagekitio/internal/type/base_page.rbi +42 -0
- data/rbi/imagekitio/internal/type/boolean.rbi +58 -0
- data/rbi/imagekitio/internal/type/converter.rbi +216 -0
- data/rbi/imagekitio/internal/type/enum.rbi +82 -0
- data/rbi/imagekitio/internal/type/file_input.rbi +59 -0
- data/rbi/imagekitio/internal/type/hash_of.rbi +104 -0
- data/rbi/imagekitio/internal/type/request_parameters.rbi +29 -0
- data/rbi/imagekitio/internal/type/union.rbi +128 -0
- data/rbi/imagekitio/internal/type/unknown.rbi +58 -0
- data/rbi/imagekitio/internal/util.rbi +487 -0
- data/rbi/imagekitio/internal.rbi +18 -0
- data/rbi/imagekitio/models/accounts/origin_create_params.rbi +81 -0
- data/rbi/imagekitio/models/accounts/origin_delete_params.rbi +34 -0
- data/rbi/imagekitio/models/accounts/origin_get_params.rbi +34 -0
- data/rbi/imagekitio/models/accounts/origin_list_params.rbi +34 -0
- data/rbi/imagekitio/models/accounts/origin_list_response.rbi +15 -0
- data/rbi/imagekitio/models/accounts/origin_request.rbi +775 -0
- data/rbi/imagekitio/models/accounts/origin_response.rbi +718 -0
- data/rbi/imagekitio/models/accounts/origin_update_params.rbi +81 -0
- data/rbi/imagekitio/models/accounts/url_endpoint_create_params.rbi +34 -0
- data/rbi/imagekitio/models/accounts/url_endpoint_delete_params.rbi +34 -0
- data/rbi/imagekitio/models/accounts/url_endpoint_get_params.rbi +34 -0
- data/rbi/imagekitio/models/accounts/url_endpoint_list_params.rbi +34 -0
- data/rbi/imagekitio/models/accounts/url_endpoint_list_response.rbi +15 -0
- data/rbi/imagekitio/models/accounts/url_endpoint_request.rbi +218 -0
- data/rbi/imagekitio/models/accounts/url_endpoint_response.rbi +213 -0
- data/rbi/imagekitio/models/accounts/url_endpoint_update_params.rbi +34 -0
- data/rbi/imagekitio/models/accounts/usage_get_params.rbi +60 -0
- data/rbi/imagekitio/models/accounts/usage_get_response.rbi +89 -0
- data/rbi/imagekitio/models/asset_list_params.rbi +281 -0
- data/rbi/imagekitio/models/asset_list_response.rbi +28 -0
- data/rbi/imagekitio/models/base_overlay.rbi +44 -0
- data/rbi/imagekitio/models/base_webhook_event.rbi +33 -0
- data/rbi/imagekitio/models/beta/v2/file_upload_params.rbi +861 -0
- data/rbi/imagekitio/models/beta/v2/file_upload_response.rbi +1197 -0
- data/rbi/imagekitio/models/cache/invalidation_create_params.rbi +45 -0
- data/rbi/imagekitio/models/cache/invalidation_create_response.rbi +37 -0
- data/rbi/imagekitio/models/cache/invalidation_get_params.rbi +34 -0
- data/rbi/imagekitio/models/cache/invalidation_get_response.rbi +93 -0
- data/rbi/imagekitio/models/custom_metadata_field.rbi +422 -0
- data/rbi/imagekitio/models/custom_metadata_field_create_params.rbi +443 -0
- data/rbi/imagekitio/models/custom_metadata_field_delete_params.rbi +30 -0
- data/rbi/imagekitio/models/custom_metadata_field_delete_response.rbi +23 -0
- data/rbi/imagekitio/models/custom_metadata_field_list_params.rbi +66 -0
- data/rbi/imagekitio/models/custom_metadata_field_list_response.rbi +11 -0
- data/rbi/imagekitio/models/custom_metadata_field_update_params.rbi +376 -0
- data/rbi/imagekitio/models/extensions.rbi +274 -0
- data/rbi/imagekitio/models/file.rbi +789 -0
- data/rbi/imagekitio/models/file_copy_params.rbi +66 -0
- data/rbi/imagekitio/models/file_copy_response.rbi +23 -0
- data/rbi/imagekitio/models/file_delete_params.rbi +27 -0
- data/rbi/imagekitio/models/file_get_params.rbi +27 -0
- data/rbi/imagekitio/models/file_move_params.rbi +51 -0
- data/rbi/imagekitio/models/file_move_response.rbi +23 -0
- data/rbi/imagekitio/models/file_rename_params.rbi +102 -0
- data/rbi/imagekitio/models/file_rename_response.rbi +35 -0
- data/rbi/imagekitio/models/file_update_params.rbi +58 -0
- data/rbi/imagekitio/models/file_update_response.rbi +322 -0
- data/rbi/imagekitio/models/file_upload_params.rbi +897 -0
- data/rbi/imagekitio/models/file_upload_response.rbi +1176 -0
- data/rbi/imagekitio/models/files/bulk_add_tags_params.rbi +56 -0
- data/rbi/imagekitio/models/files/bulk_add_tags_response.rbi +41 -0
- data/rbi/imagekitio/models/files/bulk_delete_params.rbi +48 -0
- data/rbi/imagekitio/models/files/bulk_delete_response.rbi +41 -0
- data/rbi/imagekitio/models/files/bulk_remove_ai_tags_params.rbi +56 -0
- data/rbi/imagekitio/models/files/bulk_remove_ai_tags_response.rbi +41 -0
- data/rbi/imagekitio/models/files/bulk_remove_tags_params.rbi +56 -0
- data/rbi/imagekitio/models/files/bulk_remove_tags_response.rbi +41 -0
- data/rbi/imagekitio/models/files/metadata_get_from_url_params.rbi +47 -0
- data/rbi/imagekitio/models/files/metadata_get_params.rbi +34 -0
- data/rbi/imagekitio/models/files/version_delete_params.rbi +40 -0
- data/rbi/imagekitio/models/files/version_delete_response.rbi +25 -0
- data/rbi/imagekitio/models/files/version_get_params.rbi +40 -0
- data/rbi/imagekitio/models/files/version_list_params.rbi +34 -0
- data/rbi/imagekitio/models/files/version_list_response.rbi +13 -0
- data/rbi/imagekitio/models/files/version_restore_params.rbi +40 -0
- data/rbi/imagekitio/models/folder.rbi +121 -0
- data/rbi/imagekitio/models/folder_copy_params.rbi +68 -0
- data/rbi/imagekitio/models/folder_copy_response.rbi +33 -0
- data/rbi/imagekitio/models/folder_create_params.rbi +71 -0
- data/rbi/imagekitio/models/folder_create_response.rbi +23 -0
- data/rbi/imagekitio/models/folder_delete_params.rbi +40 -0
- data/rbi/imagekitio/models/folder_delete_response.rbi +23 -0
- data/rbi/imagekitio/models/folder_move_params.rbi +53 -0
- data/rbi/imagekitio/models/folder_move_response.rbi +33 -0
- data/rbi/imagekitio/models/folder_rename_params.rbi +98 -0
- data/rbi/imagekitio/models/folder_rename_response.rbi +33 -0
- data/rbi/imagekitio/models/folders/job_get_params.rbi +34 -0
- data/rbi/imagekitio/models/folders/job_get_response.rbi +173 -0
- data/rbi/imagekitio/models/get_image_attributes_options.rbi +121 -0
- data/rbi/imagekitio/models/image_overlay.rbi +109 -0
- data/rbi/imagekitio/models/metadata.rbi +813 -0
- data/rbi/imagekitio/models/overlay.rbi +28 -0
- data/rbi/imagekitio/models/overlay_position.rbi +148 -0
- data/rbi/imagekitio/models/overlay_timing.rbi +135 -0
- data/rbi/imagekitio/models/responsive_image_attributes.rbi +74 -0
- data/rbi/imagekitio/models/solid_color_overlay.rbi +79 -0
- data/rbi/imagekitio/models/solid_color_overlay_transformation.rbi +218 -0
- data/rbi/imagekitio/models/src_options.rbi +159 -0
- data/rbi/imagekitio/models/streaming_resolution.rbi +38 -0
- data/rbi/imagekitio/models/subtitle_overlay.rbi +114 -0
- data/rbi/imagekitio/models/subtitle_overlay_transformation.rbi +215 -0
- data/rbi/imagekitio/models/text_overlay.rbi +110 -0
- data/rbi/imagekitio/models/text_overlay_transformation.rbi +451 -0
- data/rbi/imagekitio/models/transformation.rbi +1646 -0
- data/rbi/imagekitio/models/transformation_position.rbi +28 -0
- data/rbi/imagekitio/models/unsafe_unwrap_webhook_event.rbi +33 -0
- data/rbi/imagekitio/models/unwrap_webhook_event.rbi +31 -0
- data/rbi/imagekitio/models/update_file_request.rbi +316 -0
- data/rbi/imagekitio/models/upload_post_transform_error_event.rbi +434 -0
- data/rbi/imagekitio/models/upload_post_transform_success_event.rbi +327 -0
- data/rbi/imagekitio/models/upload_pre_transform_error_event.rbi +244 -0
- data/rbi/imagekitio/models/upload_pre_transform_success_event.rbi +1300 -0
- data/rbi/imagekitio/models/video_overlay.rbi +105 -0
- data/rbi/imagekitio/models/video_transformation_accepted_event.rbi +659 -0
- data/rbi/imagekitio/models/video_transformation_error_event.rbi +772 -0
- data/rbi/imagekitio/models/video_transformation_ready_event.rbi +864 -0
- data/rbi/imagekitio/models/webhook_unsafe_unwrap_params.rbi +30 -0
- data/rbi/imagekitio/models/webhook_unwrap_params.rbi +27 -0
- data/rbi/imagekitio/models.rbi +135 -0
- data/rbi/imagekitio/request_options.rbi +59 -0
- data/rbi/imagekitio/resources/accounts/origins.rbi +91 -0
- data/rbi/imagekitio/resources/accounts/url_endpoints.rbi +129 -0
- data/rbi/imagekitio/resources/accounts/usage.rbi +36 -0
- data/rbi/imagekitio/resources/accounts.rbi +21 -0
- data/rbi/imagekitio/resources/assets.rbi +74 -0
- data/rbi/imagekitio/resources/beta/v2/files.rbi +193 -0
- data/rbi/imagekitio/resources/beta/v2.rbi +17 -0
- data/rbi/imagekitio/resources/beta.rbi +15 -0
- data/rbi/imagekitio/resources/cache/invalidation.rbi +44 -0
- data/rbi/imagekitio/resources/cache.rbi +15 -0
- data/rbi/imagekitio/resources/custom_metadata_fields.rbi +106 -0
- data/rbi/imagekitio/resources/files/bulk.rbi +88 -0
- data/rbi/imagekitio/resources/files/metadata.rbi +49 -0
- data/rbi/imagekitio/resources/files/versions.rbi +89 -0
- data/rbi/imagekitio/resources/files.rbi +364 -0
- data/rbi/imagekitio/resources/folders/job.rbi +29 -0
- data/rbi/imagekitio/resources/folders.rbi +146 -0
- data/rbi/imagekitio/resources/webhooks.rbi +50 -0
- data/rbi/imagekitio/version.rbi +5 -0
- data/sig/imagekitio/client.rbs +47 -0
- data/sig/imagekitio/errors.rbs +117 -0
- data/sig/imagekitio/file_part.rbs +21 -0
- data/sig/imagekitio/helpers/helper.rbs +24 -0
- data/sig/imagekitio/internal/transport/base_client.rbs +131 -0
- data/sig/imagekitio/internal/transport/pooled_net_requester.rbs +45 -0
- data/sig/imagekitio/internal/type/array_of.rbs +48 -0
- data/sig/imagekitio/internal/type/base_model.rbs +102 -0
- data/sig/imagekitio/internal/type/base_page.rbs +24 -0
- data/sig/imagekitio/internal/type/boolean.rbs +26 -0
- data/sig/imagekitio/internal/type/converter.rbs +79 -0
- data/sig/imagekitio/internal/type/enum.rbs +32 -0
- data/sig/imagekitio/internal/type/file_input.rbs +25 -0
- data/sig/imagekitio/internal/type/hash_of.rbs +48 -0
- data/sig/imagekitio/internal/type/request_parameters.rbs +19 -0
- data/sig/imagekitio/internal/type/union.rbs +52 -0
- data/sig/imagekitio/internal/type/unknown.rbs +26 -0
- data/sig/imagekitio/internal/util.rbs +185 -0
- data/sig/imagekitio/internal.rbs +9 -0
- data/sig/imagekitio/models/accounts/origin_create_params.rbs +30 -0
- data/sig/imagekitio/models/accounts/origin_delete_params.rbs +17 -0
- data/sig/imagekitio/models/accounts/origin_get_params.rbs +17 -0
- data/sig/imagekitio/models/accounts/origin_list_params.rbs +17 -0
- data/sig/imagekitio/models/accounts/origin_list_response.rbs +10 -0
- data/sig/imagekitio/models/accounts/origin_request.rbs +468 -0
- data/sig/imagekitio/models/accounts/origin_response.rbs +418 -0
- data/sig/imagekitio/models/accounts/origin_update_params.rbs +30 -0
- data/sig/imagekitio/models/accounts/url_endpoint_create_params.rbs +17 -0
- data/sig/imagekitio/models/accounts/url_endpoint_delete_params.rbs +17 -0
- data/sig/imagekitio/models/accounts/url_endpoint_get_params.rbs +17 -0
- data/sig/imagekitio/models/accounts/url_endpoint_list_params.rbs +17 -0
- data/sig/imagekitio/models/accounts/url_endpoint_list_response.rbs +10 -0
- data/sig/imagekitio/models/accounts/url_endpoint_request.rbs +97 -0
- data/sig/imagekitio/models/accounts/url_endpoint_response.rbs +96 -0
- data/sig/imagekitio/models/accounts/url_endpoint_update_params.rbs +17 -0
- data/sig/imagekitio/models/accounts/usage_get_params.rbs +30 -0
- data/sig/imagekitio/models/accounts/usage_get_response.rbs +52 -0
- data/sig/imagekitio/models/asset_list_params.rbs +138 -0
- data/sig/imagekitio/models/asset_list_response.rbs +16 -0
- data/sig/imagekitio/models/base_overlay.rbs +31 -0
- data/sig/imagekitio/models/base_webhook_event.rbs +15 -0
- data/sig/imagekitio/models/beta/v2/file_upload_params.rbs +310 -0
- data/sig/imagekitio/models/beta/v2/file_upload_response.rbs +487 -0
- data/sig/imagekitio/models/cache/invalidation_create_params.rbs +25 -0
- data/sig/imagekitio/models/cache/invalidation_create_response.rbs +17 -0
- data/sig/imagekitio/models/cache/invalidation_get_params.rbs +17 -0
- data/sig/imagekitio/models/cache/invalidation_get_response.rbs +35 -0
- data/sig/imagekitio/models/custom_metadata_field.rbs +178 -0
- data/sig/imagekitio/models/custom_metadata_field_create_params.rbs +179 -0
- data/sig/imagekitio/models/custom_metadata_field_delete_params.rbs +15 -0
- data/sig/imagekitio/models/custom_metadata_field_delete_response.rbs +11 -0
- data/sig/imagekitio/models/custom_metadata_field_list_params.rbs +32 -0
- data/sig/imagekitio/models/custom_metadata_field_list_response.rbs +8 -0
- data/sig/imagekitio/models/custom_metadata_field_update_params.rbs +152 -0
- data/sig/imagekitio/models/extensions.rbs +132 -0
- data/sig/imagekitio/models/file.rbs +384 -0
- data/sig/imagekitio/models/file_copy_params.rbs +38 -0
- data/sig/imagekitio/models/file_copy_response.rbs +11 -0
- data/sig/imagekitio/models/file_delete_params.rbs +15 -0
- data/sig/imagekitio/models/file_get_params.rbs +14 -0
- data/sig/imagekitio/models/file_move_params.rbs +28 -0
- data/sig/imagekitio/models/file_move_response.rbs +11 -0
- data/sig/imagekitio/models/file_rename_params.rbs +34 -0
- data/sig/imagekitio/models/file_rename_response.rbs +15 -0
- data/sig/imagekitio/models/file_update_params.rbs +28 -0
- data/sig/imagekitio/models/file_update_response.rbs +120 -0
- data/sig/imagekitio/models/file_upload_params.rbs +327 -0
- data/sig/imagekitio/models/file_upload_response.rbs +483 -0
- data/sig/imagekitio/models/files/bulk_add_tags_params.rbs +30 -0
- data/sig/imagekitio/models/files/bulk_add_tags_response.rbs +20 -0
- data/sig/imagekitio/models/files/bulk_delete_params.rbs +26 -0
- data/sig/imagekitio/models/files/bulk_delete_response.rbs +20 -0
- data/sig/imagekitio/models/files/bulk_remove_ai_tags_params.rbs +30 -0
- data/sig/imagekitio/models/files/bulk_remove_ai_tags_response.rbs +20 -0
- data/sig/imagekitio/models/files/bulk_remove_tags_params.rbs +30 -0
- data/sig/imagekitio/models/files/bulk_remove_tags_response.rbs +20 -0
- data/sig/imagekitio/models/files/metadata_get_from_url_params.rbs +25 -0
- data/sig/imagekitio/models/files/metadata_get_params.rbs +17 -0
- data/sig/imagekitio/models/files/version_delete_params.rbs +25 -0
- data/sig/imagekitio/models/files/version_delete_response.rbs +13 -0
- data/sig/imagekitio/models/files/version_get_params.rbs +25 -0
- data/sig/imagekitio/models/files/version_list_params.rbs +17 -0
- data/sig/imagekitio/models/files/version_list_response.rbs +9 -0
- data/sig/imagekitio/models/files/version_restore_params.rbs +25 -0
- data/sig/imagekitio/models/folder.rbs +69 -0
- data/sig/imagekitio/models/folder_copy_params.rbs +38 -0
- data/sig/imagekitio/models/folder_copy_response.rbs +13 -0
- data/sig/imagekitio/models/folder_create_params.rbs +28 -0
- data/sig/imagekitio/models/folder_create_response.rbs +11 -0
- data/sig/imagekitio/models/folder_delete_params.rbs +23 -0
- data/sig/imagekitio/models/folder_delete_response.rbs +11 -0
- data/sig/imagekitio/models/folder_move_params.rbs +28 -0
- data/sig/imagekitio/models/folder_move_response.rbs +13 -0
- data/sig/imagekitio/models/folder_rename_params.rbs +34 -0
- data/sig/imagekitio/models/folder_rename_response.rbs +13 -0
- data/sig/imagekitio/models/folders/job_get_params.rbs +17 -0
- data/sig/imagekitio/models/folders/job_get_response.rbs +72 -0
- data/sig/imagekitio/models/get_image_attributes_options.rbs +43 -0
- data/sig/imagekitio/models/image_overlay.rbs +59 -0
- data/sig/imagekitio/models/metadata.rbs +546 -0
- data/sig/imagekitio/models/overlay.rbs +16 -0
- data/sig/imagekitio/models/overlay_position.rbs +85 -0
- data/sig/imagekitio/models/overlay_timing.rbs +66 -0
- data/sig/imagekitio/models/responsive_image_attributes.rbs +36 -0
- data/sig/imagekitio/models/solid_color_overlay.rbs +38 -0
- data/sig/imagekitio/models/solid_color_overlay_transformation.rbs +97 -0
- data/sig/imagekitio/models/src_options.rbs +64 -0
- data/sig/imagekitio/models/streaming_resolution.rbs +20 -0
- data/sig/imagekitio/models/subtitle_overlay.rbs +59 -0
- data/sig/imagekitio/models/subtitle_overlay_transformation.rbs +78 -0
- data/sig/imagekitio/models/text_overlay.rbs +59 -0
- data/sig/imagekitio/models/text_overlay_transformation.rbs +195 -0
- data/sig/imagekitio/models/transformation.rbs +763 -0
- data/sig/imagekitio/models/transformation_position.rbs +14 -0
- data/sig/imagekitio/models/unsafe_unwrap_webhook_event.rbs +18 -0
- data/sig/imagekitio/models/unwrap_webhook_event.rbs +18 -0
- data/sig/imagekitio/models/update_file_request.rbs +122 -0
- data/sig/imagekitio/models/upload_post_transform_error_event.rbs +192 -0
- data/sig/imagekitio/models/upload_post_transform_success_event.rbs +142 -0
- data/sig/imagekitio/models/upload_pre_transform_error_event.rbs +115 -0
- data/sig/imagekitio/models/upload_pre_transform_success_event.rbs +541 -0
- data/sig/imagekitio/models/video_overlay.rbs +59 -0
- data/sig/imagekitio/models/video_transformation_accepted_event.rbs +261 -0
- data/sig/imagekitio/models/video_transformation_error_event.rbs +300 -0
- data/sig/imagekitio/models/video_transformation_ready_event.rbs +359 -0
- data/sig/imagekitio/models/webhook_unsafe_unwrap_params.rbs +15 -0
- data/sig/imagekitio/models/webhook_unwrap_params.rbs +15 -0
- data/sig/imagekitio/models.rbs +119 -0
- data/sig/imagekitio/request_options.rbs +36 -0
- data/sig/imagekitio/resources/accounts/origins.rbs +34 -0
- data/sig/imagekitio/resources/accounts/url_endpoints.rbs +40 -0
- data/sig/imagekitio/resources/accounts/usage.rbs +15 -0
- data/sig/imagekitio/resources/accounts.rbs +13 -0
- data/sig/imagekitio/resources/assets.rbs +18 -0
- data/sig/imagekitio/resources/beta/v2/files.rbs +35 -0
- data/sig/imagekitio/resources/beta/v2.rbs +11 -0
- data/sig/imagekitio/resources/beta.rbs +9 -0
- data/sig/imagekitio/resources/cache/invalidation.rbs +19 -0
- data/sig/imagekitio/resources/cache.rbs +9 -0
- data/sig/imagekitio/resources/custom_metadata_fields.rbs +32 -0
- data/sig/imagekitio/resources/files/bulk.rbs +32 -0
- data/sig/imagekitio/resources/files/metadata.rbs +19 -0
- data/sig/imagekitio/resources/files/versions.rbs +32 -0
- data/sig/imagekitio/resources/files.rbs +76 -0
- data/sig/imagekitio/resources/folders/job.rbs +14 -0
- data/sig/imagekitio/resources/folders.rbs +40 -0
- data/sig/imagekitio/resources/webhooks.rbs +27 -0
- data/sig/imagekitio/version.rbs +3 -0
- metadata +470 -136
- data/Rakefile +0 -27
- data/lib/active_storage/active_storage.rb +0 -7
- data/lib/active_storage/service/ik_file.rb +0 -115
- data/lib/active_storage/service/image_kit_io_service.rb +0 -188
- data/lib/carrierwave/carrierwave.rb +0 -83
- data/lib/carrierwave/storage/ik_file.rb +0 -51
- data/lib/carrierwave/storage/imagekit_store.rb +0 -68
- data/lib/carrierwave/support/uri_filename.rb +0 -12
- data/lib/imagekitio/api_service/bulk.rb +0 -58
- data/lib/imagekitio/api_service/custom_metadata_field.rb +0 -52
- data/lib/imagekitio/api_service/file.rb +0 -221
- data/lib/imagekitio/api_service/folder.rb +0 -49
- data/lib/imagekitio/base.rb +0 -12
- data/lib/imagekitio/configurable.rb +0 -43
- data/lib/imagekitio/constant.rb +0 -36
- data/lib/imagekitio/constants/default.rb +0 -22
- data/lib/imagekitio/constants/error.rb +0 -69
- data/lib/imagekitio/constants/file.rb +0 -11
- data/lib/imagekitio/constants/supported_transformation.rb +0 -39
- data/lib/imagekitio/constants/url.rb +0 -14
- data/lib/imagekitio/railtie.rb +0 -4
- data/lib/imagekitio/request.rb +0 -98
- data/lib/imagekitio/sdk/version.rb +0 -5
- data/lib/imagekitio/url.rb +0 -216
- data/lib/imagekitio/utils/calculation.rb +0 -45
- data/lib/imagekitio/utils/formatter.rb +0 -48
- data/lib/imagekitio/utils/option_validator.rb +0 -36
- data/lib/tasks/imagekitio/imagekitio_tasks.rake +0 -4
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "transformation_utils"
|
|
4
|
+
require_relative "crypto_utils"
|
|
5
|
+
require_relative "uuid_utils"
|
|
6
|
+
|
|
7
|
+
module Imagekitio
|
|
8
|
+
class Helper
|
|
9
|
+
TRANSFORMATION_PARAMETER = "tr"
|
|
10
|
+
SIGNATURE_PARAMETER = "ik-s"
|
|
11
|
+
TIMESTAMP_PARAMETER = "ik-t"
|
|
12
|
+
DEFAULT_TIMESTAMP = 9_999_999_999
|
|
13
|
+
SIMPLE_OVERLAY_PATH_REGEX = %r{^[a-zA-Z0-9\-._/ ]*$}
|
|
14
|
+
SIMPLE_OVERLAY_TEXT_REGEX = /^[a-zA-Z0-9\-._ ]*$/
|
|
15
|
+
|
|
16
|
+
private_constant :TRANSFORMATION_PARAMETER,
|
|
17
|
+
:SIGNATURE_PARAMETER,
|
|
18
|
+
:TIMESTAMP_PARAMETER,
|
|
19
|
+
:DEFAULT_TIMESTAMP,
|
|
20
|
+
:SIMPLE_OVERLAY_PATH_REGEX,
|
|
21
|
+
:SIMPLE_OVERLAY_TEXT_REGEX
|
|
22
|
+
|
|
23
|
+
# Builds a URL with transformations applied
|
|
24
|
+
#
|
|
25
|
+
# @param options [Imagekitio::Models::SrcOptions] Options for generating ImageKit URLs with transformations
|
|
26
|
+
# @return [String] The built URL with transformations
|
|
27
|
+
def build_url(options)
|
|
28
|
+
# Convert model to hash - all inputs are expected to be BaseModel objects
|
|
29
|
+
opts = options.to_h
|
|
30
|
+
|
|
31
|
+
# Set defaults
|
|
32
|
+
opts[:url_endpoint] ||= ""
|
|
33
|
+
opts[:src] ||= ""
|
|
34
|
+
opts[:transformation_position] ||= :query
|
|
35
|
+
|
|
36
|
+
return "" if opts[:src].nil? || opts[:src].empty?
|
|
37
|
+
|
|
38
|
+
src = opts[:src].to_s
|
|
39
|
+
is_absolute_url = src.start_with?("http://", "https://")
|
|
40
|
+
|
|
41
|
+
begin
|
|
42
|
+
if is_absolute_url
|
|
43
|
+
url_obj = URI.parse(src)
|
|
44
|
+
is_src_parameter_used_for_url = true
|
|
45
|
+
else
|
|
46
|
+
url_obj = URI.parse(opts[:url_endpoint].to_s)
|
|
47
|
+
end
|
|
48
|
+
rescue URI::InvalidURIError
|
|
49
|
+
return ""
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Add query parameters
|
|
53
|
+
query_params = opts[:query_parameters] || {}
|
|
54
|
+
existing_params = CGI.parse(url_obj.query || "")
|
|
55
|
+
query_params.each do |key, value|
|
|
56
|
+
existing_params[key.to_s] = [value.to_s]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Build transformation string
|
|
60
|
+
transformation_string = build_transformation_string(opts[:transformation])
|
|
61
|
+
|
|
62
|
+
add_as_query = Imagekitio::TransformationUtils.add_as_query_parameter?(opts) ||
|
|
63
|
+
is_src_parameter_used_for_url
|
|
64
|
+
transformation_placeholder = "PLEASEREPLACEJUSTBEFORESIGN"
|
|
65
|
+
|
|
66
|
+
unless is_absolute_url
|
|
67
|
+
# For non-absolute URLs, construct the path
|
|
68
|
+
endpoint_path = url_obj.path
|
|
69
|
+
path_parts = []
|
|
70
|
+
|
|
71
|
+
# Add endpoint path if it's not empty
|
|
72
|
+
if !endpoint_path.empty? && endpoint_path != "/"
|
|
73
|
+
path_parts << endpoint_path
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if !transformation_string.empty? && !add_as_query
|
|
77
|
+
path_parts << "#{TRANSFORMATION_PARAMETER}#{Imagekitio::TransformationUtils.get_chain_transform_delimiter}#{transformation_placeholder}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
path_parts << src
|
|
81
|
+
url_obj.path = path_join(path_parts)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Build query string
|
|
85
|
+
unless existing_params.empty?
|
|
86
|
+
url_obj.query = existing_params.map { |k, v| "#{CGI.escape(k)}=#{CGI.escape(v.first)}" }.join("&")
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Build final URL
|
|
90
|
+
final_url = url_obj.to_s
|
|
91
|
+
|
|
92
|
+
# Add transformation parameter manually to avoid URL encoding
|
|
93
|
+
if !transformation_string.empty? && add_as_query
|
|
94
|
+
separator = url_obj.query && !url_obj.query.empty? ? "&" : "?"
|
|
95
|
+
final_url = "#{final_url}#{separator}#{TRANSFORMATION_PARAMETER}=#{transformation_placeholder}"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Replace placeholder with actual transformation string
|
|
99
|
+
unless transformation_string.empty?
|
|
100
|
+
final_url = final_url.gsub(transformation_placeholder, transformation_string)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Sign the URL if needed
|
|
104
|
+
if opts[:signed] == true || (opts[:expires_in] && opts[:expires_in].to_i.positive?)
|
|
105
|
+
expiry_timestamp = get_signature_timestamp(opts[:expires_in])
|
|
106
|
+
|
|
107
|
+
url_signature = get_signature(
|
|
108
|
+
private_key: @client.private_key,
|
|
109
|
+
url: final_url,
|
|
110
|
+
url_endpoint: opts[:url_endpoint].to_s,
|
|
111
|
+
expiry_timestamp: expiry_timestamp
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
# Add signature parameters
|
|
115
|
+
final_url_uri = URI.parse(final_url)
|
|
116
|
+
has_existing_params = final_url_uri.query && !final_url_uri.query.empty?
|
|
117
|
+
separator = has_existing_params ? "&" : "?"
|
|
118
|
+
|
|
119
|
+
if expiry_timestamp && expiry_timestamp != DEFAULT_TIMESTAMP
|
|
120
|
+
final_url = "#{final_url}#{separator}#{TIMESTAMP_PARAMETER}=#{expiry_timestamp}"
|
|
121
|
+
final_url = "#{final_url}&#{SIGNATURE_PARAMETER}=#{url_signature}"
|
|
122
|
+
else
|
|
123
|
+
final_url = "#{final_url}#{separator}#{SIGNATURE_PARAMETER}=#{url_signature}"
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
final_url
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Generates transformation string from transformation objects
|
|
131
|
+
#
|
|
132
|
+
# @param transformations [Array<Imagekitio::Models::Transformation>] Array of transformation objects
|
|
133
|
+
# @return [String] The transformation string (e.g., "w-400,h-300")
|
|
134
|
+
def build_transformation_string(transformations)
|
|
135
|
+
return "" unless transformations.is_a?(Array)
|
|
136
|
+
|
|
137
|
+
parsed_transforms = []
|
|
138
|
+
|
|
139
|
+
# rubocop:disable Metrics/BlockLength
|
|
140
|
+
transformations.each do |transform|
|
|
141
|
+
next unless transform
|
|
142
|
+
|
|
143
|
+
# Convert model to hash - all transformation inputs are expected to be BaseModel objects
|
|
144
|
+
current_transform = transform.to_h
|
|
145
|
+
|
|
146
|
+
parsed_transform_step = []
|
|
147
|
+
|
|
148
|
+
# rubocop:disable Metrics/BlockLength
|
|
149
|
+
current_transform.each do |key, value|
|
|
150
|
+
next if value.nil? || value.to_s.empty?
|
|
151
|
+
|
|
152
|
+
# Handle overlay separately
|
|
153
|
+
if key.to_s == "overlay" && value
|
|
154
|
+
# Pass model object directly to process_overlay
|
|
155
|
+
raw_string = process_overlay(value)
|
|
156
|
+
if raw_string && !raw_string.strip.empty?
|
|
157
|
+
parsed_transform_step << raw_string
|
|
158
|
+
end
|
|
159
|
+
next
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
transform_key = Imagekitio::TransformationUtils.get_transform_key(key)
|
|
163
|
+
transform_key = key.to_s if transform_key.empty?
|
|
164
|
+
|
|
165
|
+
next if transform_key.empty?
|
|
166
|
+
|
|
167
|
+
# Handle special boolean effects
|
|
168
|
+
boolean_effects = %w[e-grayscale e-contrast e-removedotbg e-bgremove e-upscale e-retouch e-genvar]
|
|
169
|
+
if boolean_effects.include?(transform_key)
|
|
170
|
+
if value == true || value == "-" || value == "true"
|
|
171
|
+
parsed_transform_step << transform_key
|
|
172
|
+
end
|
|
173
|
+
next
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# Handle effects that can be boolean or have values
|
|
177
|
+
value_effects = %w[e-sharpen e-shadow e-gradient e-usm e-dropshadow]
|
|
178
|
+
if value_effects.include?(transform_key) &&
|
|
179
|
+
(value.to_s.strip.empty? || value == true || value == "true")
|
|
180
|
+
parsed_transform_step << transform_key
|
|
181
|
+
next
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Handle raw parameter
|
|
185
|
+
if key.to_s == "raw"
|
|
186
|
+
parsed_transform_step << value.to_s
|
|
187
|
+
next
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# Handle special cases for di and ff (need special encoding)
|
|
191
|
+
if %w[di ff].include?(transform_key)
|
|
192
|
+
processed_value = remove_leading_slash(remove_trailing_slash(value.to_s))
|
|
193
|
+
processed_value = processed_value.gsub("/", "@@")
|
|
194
|
+
value = processed_value
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# Handle streaming resolutions array
|
|
198
|
+
if transform_key == "sr" && value.is_a?(Array)
|
|
199
|
+
value = value.join("_")
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Special case for trim with empty string
|
|
203
|
+
if transform_key == "t" && value.to_s.strip.empty?
|
|
204
|
+
value = "true"
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# Convert numeric values to integers if they're whole numbers
|
|
208
|
+
if value.is_a?(Numeric)
|
|
209
|
+
value = value.to_i if value == value.to_i
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
parsed_transform_step << "#{transform_key}#{Imagekitio::TransformationUtils.get_transform_key_value_delimiter}#{value}"
|
|
213
|
+
end
|
|
214
|
+
# rubocop:enable Metrics/BlockLength
|
|
215
|
+
|
|
216
|
+
unless parsed_transform_step.empty?
|
|
217
|
+
parsed_transforms << parsed_transform_step.join(Imagekitio::TransformationUtils.get_transform_delimiter)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
# rubocop:enable Metrics/BlockLength
|
|
221
|
+
|
|
222
|
+
parsed_transforms.join(Imagekitio::TransformationUtils.get_chain_transform_delimiter)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Generates authentication parameters for client-side file uploads using ImageKit's Upload API V1.
|
|
226
|
+
#
|
|
227
|
+
# This method creates the required authentication signature that allows secure file uploads
|
|
228
|
+
# directly from the browser or mobile applications without exposing your private API key.
|
|
229
|
+
# The generated parameters include a unique token, expiration timestamp, and HMAC signature.
|
|
230
|
+
#
|
|
231
|
+
# @param token [String, nil] Custom token for the upload session. If not provided, a UUID v4 will be generated automatically.
|
|
232
|
+
# @param expire [Integer, nil] Expiration time in seconds from now. If not provided, defaults to 1800 seconds (30 minutes).
|
|
233
|
+
# @return [Hash{Symbol => String, Integer}] Authentication parameters object containing:
|
|
234
|
+
# - :token (String): Unique identifier for this upload session
|
|
235
|
+
# - :expire (Integer): Unix timestamp when these parameters expire
|
|
236
|
+
# - :signature (String): HMAC-SHA1 signature for authenticating the upload
|
|
237
|
+
def get_authentication_parameters(token: nil, expire: nil)
|
|
238
|
+
default_time_diff = 60 * 30
|
|
239
|
+
default_expire = Time.now.to_i + default_time_diff
|
|
240
|
+
|
|
241
|
+
# Handle falsy values - empty string and nil should generate new token
|
|
242
|
+
final_token = token.nil? || token.to_s.empty? ? generate_token : token
|
|
243
|
+
# Handle falsy values - nil and 0 should use default expire
|
|
244
|
+
final_expire = expire.nil? || expire.zero? ? default_expire : expire
|
|
245
|
+
|
|
246
|
+
get_authentication_parameters_internal(final_token, final_expire, @client.private_key)
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
# Generates responsive image attributes for use in HTML <img> tags.
|
|
250
|
+
#
|
|
251
|
+
# This method creates optimized srcset and sizes attributes for responsive images,
|
|
252
|
+
# enabling browsers to select the most appropriate image size based on the device's
|
|
253
|
+
# screen width and resolution. Supports three strategies:
|
|
254
|
+
# - Width-based (w descriptors): When sizes attribute is provided
|
|
255
|
+
# - DPR-based (x descriptors): When width is provided without sizes
|
|
256
|
+
# - Fallback (w descriptors): Uses device breakpoints when neither is provided
|
|
257
|
+
#
|
|
258
|
+
# @param options [Imagekitio::Models::GetImageAttributesOptions] Options for generating responsive image attributes
|
|
259
|
+
# @return [Imagekitio::Models::ResponsiveImageAttributes] Responsive image attributes suitable for an HTML <img> element
|
|
260
|
+
def get_responsive_image_attributes(options)
|
|
261
|
+
# Convert model to hash for easier access
|
|
262
|
+
opts = options.is_a?(Imagekitio::Internal::Type::BaseModel) ? options.to_h : options
|
|
263
|
+
|
|
264
|
+
# Default breakpoint pools
|
|
265
|
+
default_device_breakpoints = [640, 750, 828, 1080, 1200, 1920, 2048, 3840]
|
|
266
|
+
default_image_breakpoints = [16, 32, 48, 64, 96, 128, 256, 384]
|
|
267
|
+
|
|
268
|
+
# Extract options
|
|
269
|
+
src = opts[:src]
|
|
270
|
+
url_endpoint = opts[:url_endpoint]
|
|
271
|
+
width = opts[:width]
|
|
272
|
+
sizes = opts[:sizes]
|
|
273
|
+
device_breakpoints = opts[:device_breakpoints] || default_device_breakpoints
|
|
274
|
+
image_breakpoints = opts[:image_breakpoints] || default_image_breakpoints
|
|
275
|
+
transformation = opts[:transformation] || []
|
|
276
|
+
transformation_position = opts[:transformation_position]
|
|
277
|
+
query_parameters = opts[:query_parameters]
|
|
278
|
+
expires_in = opts[:expires_in]
|
|
279
|
+
signed = opts[:signed]
|
|
280
|
+
|
|
281
|
+
# Sort and merge breakpoints
|
|
282
|
+
sorted_device_breakpoints = device_breakpoints.sort
|
|
283
|
+
sorted_image_breakpoints = image_breakpoints.sort
|
|
284
|
+
all_breakpoints = (sorted_image_breakpoints + sorted_device_breakpoints).sort.uniq
|
|
285
|
+
|
|
286
|
+
# Compute candidate widths and descriptor kind
|
|
287
|
+
result = compute_candidate_widths(
|
|
288
|
+
all_breakpoints: all_breakpoints,
|
|
289
|
+
device_breakpoints: sorted_device_breakpoints,
|
|
290
|
+
explicit_width: width,
|
|
291
|
+
sizes_attr: sizes
|
|
292
|
+
)
|
|
293
|
+
candidates = result[:candidates]
|
|
294
|
+
descriptor_kind = result[:descriptor_kind]
|
|
295
|
+
|
|
296
|
+
# Helper to build a single ImageKit URL
|
|
297
|
+
build_url_fn = lambda do |w|
|
|
298
|
+
build_url(
|
|
299
|
+
Imagekitio::Models::SrcOptions.new(
|
|
300
|
+
src: src,
|
|
301
|
+
url_endpoint: url_endpoint,
|
|
302
|
+
query_parameters: query_parameters,
|
|
303
|
+
transformation_position: transformation_position,
|
|
304
|
+
expires_in: expires_in,
|
|
305
|
+
signed: signed,
|
|
306
|
+
transformation: transformation + [
|
|
307
|
+
Imagekitio::Models::Transformation.new(width: w, crop: "at_max") # never upscale beyond original
|
|
308
|
+
]
|
|
309
|
+
)
|
|
310
|
+
)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# Build srcset
|
|
314
|
+
src_set_entries = candidates.map.with_index do |w, i|
|
|
315
|
+
# Ensure width is an integer for proper descriptor format (e.g., "640w" not "640.0w")
|
|
316
|
+
width_int = w.to_i
|
|
317
|
+
descriptor = descriptor_kind == :w ? "#{width_int}w" : "#{i + 1}x"
|
|
318
|
+
"#{build_url_fn.call(width_int)} #{descriptor}"
|
|
319
|
+
end
|
|
320
|
+
src_set = src_set_entries.empty? ? nil : src_set_entries.join(", ")
|
|
321
|
+
|
|
322
|
+
final_sizes = sizes || (descriptor_kind == :w ? "100vw" : nil)
|
|
323
|
+
|
|
324
|
+
# Build and return ResponsiveImageAttributes model
|
|
325
|
+
Imagekitio::Models::ResponsiveImageAttributes.new(
|
|
326
|
+
src: build_url_fn.call(candidates.last.to_i), # largest candidate as integer
|
|
327
|
+
src_set: src_set,
|
|
328
|
+
sizes: final_sizes,
|
|
329
|
+
width: width
|
|
330
|
+
)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# @api private
|
|
334
|
+
#
|
|
335
|
+
# @param client [Imagekitio::Client]
|
|
336
|
+
def initialize(client:)
|
|
337
|
+
@client = client
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
private
|
|
341
|
+
|
|
342
|
+
# Compute candidate widths for responsive images.
|
|
343
|
+
# Implements three strategies:
|
|
344
|
+
# 1. Width-based srcSet (w) when sizes attribute contains vw units
|
|
345
|
+
# 2. Fallback to device breakpoints when no width or sizes provided
|
|
346
|
+
# 3. DPR-based srcSet (x) with 1x and 2x variants when width is provided
|
|
347
|
+
def compute_candidate_widths(
|
|
348
|
+
all_breakpoints:,
|
|
349
|
+
device_breakpoints:,
|
|
350
|
+
explicit_width: nil,
|
|
351
|
+
sizes_attr: nil
|
|
352
|
+
)
|
|
353
|
+
# Strategy 1: Width-based srcSet (w) using viewport vw hints
|
|
354
|
+
if sizes_attr
|
|
355
|
+
vw_tokens = sizes_attr.scan(/(?:^|\s)(1?\d{1,2})vw/).flatten.map(&:to_i)
|
|
356
|
+
|
|
357
|
+
if vw_tokens.any?
|
|
358
|
+
# Find the smallest vw percentage
|
|
359
|
+
smallest_ratio = vw_tokens.min / 100.0
|
|
360
|
+
# Calculate minimum required pixels
|
|
361
|
+
min_required_px = device_breakpoints.first * smallest_ratio
|
|
362
|
+
# Filter breakpoints >= min_required_px
|
|
363
|
+
candidates = all_breakpoints.select { |bp| bp >= min_required_px }
|
|
364
|
+
return {candidates: candidates, descriptor_kind: :w}
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
# No usable vw found: fallback to all breakpoints
|
|
368
|
+
return {candidates: all_breakpoints, descriptor_kind: :w}
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
# Strategy 2: Fallback using device breakpoints if no explicit width
|
|
372
|
+
return {candidates: device_breakpoints, descriptor_kind: :w} unless explicit_width
|
|
373
|
+
|
|
374
|
+
# Strategy 3: Use 1x and 2x nearest breakpoints for x descriptor
|
|
375
|
+
# Find the first breakpoint >= target (or use the largest)
|
|
376
|
+
nearest = lambda do |target|
|
|
377
|
+
all_breakpoints.find { |bp| bp >= target } || all_breakpoints.last
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
# Generate unique 1x and 2x variants
|
|
381
|
+
unique = [nearest.call(explicit_width), nearest.call(explicit_width * 2)].uniq
|
|
382
|
+
|
|
383
|
+
{candidates: unique, descriptor_kind: :x}
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
# Generate a 32-character hex token
|
|
387
|
+
def generate_token
|
|
388
|
+
# Generate 16 random bytes and convert to hex (32 characters)
|
|
389
|
+
require("securerandom")
|
|
390
|
+
SecureRandom.hex(16)
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
# Internal method to generate authentication parameters
|
|
394
|
+
def get_authentication_parameters_internal(token, expire, private_key)
|
|
395
|
+
auth_parameters = {
|
|
396
|
+
token: token,
|
|
397
|
+
expire: expire,
|
|
398
|
+
signature: ""
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
signature = Imagekitio::CryptoUtils.create_hmac_sha1(private_key, token.to_s + expire.to_s)
|
|
402
|
+
auth_parameters[:signature] = signature
|
|
403
|
+
|
|
404
|
+
auth_parameters
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# Remove trailing slash from string
|
|
408
|
+
def remove_trailing_slash(str)
|
|
409
|
+
return str unless str.is_a?(String) && str.end_with?("/")
|
|
410
|
+
str.chomp("/")
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
# Remove leading slash from string
|
|
414
|
+
def remove_leading_slash(str)
|
|
415
|
+
return str unless str.is_a?(String) && str.start_with?("/")
|
|
416
|
+
str[1..]
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
# RFC 3986 path encoding - matches Node.js encodeURIPath exactly
|
|
420
|
+
# From Node.js: str.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent)
|
|
421
|
+
def encode_uri_path(str)
|
|
422
|
+
# Only encode characters that are NOT in the RFC 3986 path character set
|
|
423
|
+
# unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
|
424
|
+
# sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
|
|
425
|
+
# pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
|
426
|
+
str.gsub(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/) { |match| CGI.escape(match) }
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
# Join path parts (Node.js pathJoin algorithm without encoding)
|
|
430
|
+
def path_join(parts, separator = "/")
|
|
431
|
+
return "" if parts.nil? || parts.empty?
|
|
432
|
+
|
|
433
|
+
# Clean up parts and join
|
|
434
|
+
cleaned_parts = []
|
|
435
|
+
|
|
436
|
+
parts.each do |part|
|
|
437
|
+
part = part.to_s.strip
|
|
438
|
+
next if part.empty?
|
|
439
|
+
|
|
440
|
+
# Remove leading slashes from all parts
|
|
441
|
+
part = part[1..] while part.start_with?(separator)
|
|
442
|
+
|
|
443
|
+
# Remove trailing slashes from all parts
|
|
444
|
+
part = part[0..-2] while part.end_with?(separator)
|
|
445
|
+
|
|
446
|
+
cleaned_parts << part unless part.empty?
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
return "" if cleaned_parts.empty?
|
|
450
|
+
|
|
451
|
+
# Join with separator and add leading slash (Node.js style)
|
|
452
|
+
result = separator + cleaned_parts.join(separator)
|
|
453
|
+
|
|
454
|
+
# Apply encoding to special characters only, preserving path structure
|
|
455
|
+
result.gsub(/[^\x00-\x7F]/) { |char| CGI.escape(char) }
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
# Process overlay transformation (full implementation)
|
|
459
|
+
def process_overlay(overlay)
|
|
460
|
+
return "" unless overlay
|
|
461
|
+
|
|
462
|
+
# Support both BaseModel objects and plain hashes
|
|
463
|
+
type = if overlay.is_a?(Hash)
|
|
464
|
+
overlay[:type] || overlay["type"]
|
|
465
|
+
else
|
|
466
|
+
overlay.type
|
|
467
|
+
end
|
|
468
|
+
return "" unless type
|
|
469
|
+
|
|
470
|
+
# Determine overlay type based on explicit type field
|
|
471
|
+
case type.to_s
|
|
472
|
+
when "text"
|
|
473
|
+
process_text_overlay(overlay)
|
|
474
|
+
when "image"
|
|
475
|
+
process_image_overlay(overlay)
|
|
476
|
+
when "video"
|
|
477
|
+
process_video_overlay(overlay)
|
|
478
|
+
when "subtitle"
|
|
479
|
+
process_subtitle_overlay(overlay)
|
|
480
|
+
when "solidColor"
|
|
481
|
+
process_solid_color_overlay(overlay)
|
|
482
|
+
else
|
|
483
|
+
""
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
# Process input path for image/video/subtitle overlays (matching Node.js processInputPath)
|
|
488
|
+
def process_input_path(str, encoding)
|
|
489
|
+
# Remove leading and trailing slashes
|
|
490
|
+
str = remove_trailing_slash(remove_leading_slash(str))
|
|
491
|
+
|
|
492
|
+
case encoding.to_s
|
|
493
|
+
when "plain"
|
|
494
|
+
"i-#{str.gsub('/', '@@')}"
|
|
495
|
+
when "base64"
|
|
496
|
+
"ie-#{CGI.escape(Base64.strict_encode64(str))}"
|
|
497
|
+
else # auto
|
|
498
|
+
if str.match?(SIMPLE_OVERLAY_PATH_REGEX)
|
|
499
|
+
"i-#{str.gsub('/', '@@')}"
|
|
500
|
+
else
|
|
501
|
+
"ie-#{CGI.escape(Base64.strict_encode64(str))}"
|
|
502
|
+
end
|
|
503
|
+
end
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
# Process text content for text overlays (matching Node.js processText)
|
|
507
|
+
def process_text(str, encoding)
|
|
508
|
+
case encoding.to_s
|
|
509
|
+
when "plain"
|
|
510
|
+
"i-#{uri_encode(str)}"
|
|
511
|
+
when "base64"
|
|
512
|
+
"ie-#{uri_encode(Base64.strict_encode64(str))}"
|
|
513
|
+
else # auto
|
|
514
|
+
if str.match?(SIMPLE_OVERLAY_TEXT_REGEX)
|
|
515
|
+
"i-#{uri_encode(str)}"
|
|
516
|
+
else
|
|
517
|
+
"ie-#{uri_encode(Base64.strict_encode64(str))}"
|
|
518
|
+
end
|
|
519
|
+
end
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
# URI encode like JavaScript's encodeURIComponent (uses %20 instead of +)
|
|
523
|
+
def uri_encode(str)
|
|
524
|
+
CGI.escape(str).gsub("+", "%20")
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
# Process text overlay
|
|
528
|
+
def process_text_overlay(overlay)
|
|
529
|
+
text = safe_get(overlay, :text)
|
|
530
|
+
return "" unless text && !text.to_s.empty?
|
|
531
|
+
|
|
532
|
+
parts = ["l-text"]
|
|
533
|
+
|
|
534
|
+
# Handle encoding using the processText function
|
|
535
|
+
encoding = safe_get(overlay, :encoding) || "auto"
|
|
536
|
+
parts << process_text(text, encoding)
|
|
537
|
+
|
|
538
|
+
# Add other overlay properties (position, timing, transformations)
|
|
539
|
+
add_overlay_properties(parts, overlay)
|
|
540
|
+
|
|
541
|
+
parts << "l-end"
|
|
542
|
+
parts.join(",")
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
# Process image overlay
|
|
546
|
+
def process_image_overlay(overlay)
|
|
547
|
+
input = safe_get(overlay, :input)
|
|
548
|
+
return "" unless input && !input.to_s.empty?
|
|
549
|
+
|
|
550
|
+
parts = ["l-image"]
|
|
551
|
+
|
|
552
|
+
# Handle encoding using the process_input_path function
|
|
553
|
+
encoding = safe_get(overlay, :encoding) || "auto"
|
|
554
|
+
parts << process_input_path(input, encoding)
|
|
555
|
+
|
|
556
|
+
# Add other overlay properties
|
|
557
|
+
add_overlay_properties(parts, overlay)
|
|
558
|
+
|
|
559
|
+
parts << "l-end"
|
|
560
|
+
parts.join(",")
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
# Process video overlay
|
|
564
|
+
def process_video_overlay(overlay)
|
|
565
|
+
input = safe_get(overlay, :input)
|
|
566
|
+
return "" unless input && !input.to_s.empty?
|
|
567
|
+
|
|
568
|
+
parts = ["l-video"]
|
|
569
|
+
|
|
570
|
+
# Handle encoding using the process_input_path function
|
|
571
|
+
encoding = safe_get(overlay, :encoding) || "auto"
|
|
572
|
+
parts << process_input_path(input, encoding)
|
|
573
|
+
|
|
574
|
+
# Add other overlay properties
|
|
575
|
+
add_overlay_properties(parts, overlay)
|
|
576
|
+
|
|
577
|
+
parts << "l-end"
|
|
578
|
+
parts.join(",")
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
# Process subtitle overlay
|
|
582
|
+
def process_subtitle_overlay(overlay)
|
|
583
|
+
input = safe_get(overlay, :input)
|
|
584
|
+
return "" unless input && !input.to_s.empty?
|
|
585
|
+
|
|
586
|
+
parts = ["l-subtitle"]
|
|
587
|
+
|
|
588
|
+
# Handle encoding using the process_input_path function
|
|
589
|
+
encoding = safe_get(overlay, :encoding) || "auto"
|
|
590
|
+
parts << process_input_path(input, encoding)
|
|
591
|
+
|
|
592
|
+
# Add other overlay properties
|
|
593
|
+
add_overlay_properties(parts, overlay)
|
|
594
|
+
|
|
595
|
+
parts << "l-end"
|
|
596
|
+
parts.join(",")
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
# Process solid color overlay
|
|
600
|
+
def process_solid_color_overlay(overlay)
|
|
601
|
+
color = safe_get(overlay, :color)
|
|
602
|
+
return "" unless color && !color.to_s.empty?
|
|
603
|
+
|
|
604
|
+
parts = ["l-image", "i-ik_canvas", "bg-#{color}"]
|
|
605
|
+
|
|
606
|
+
# Add other overlay properties
|
|
607
|
+
add_overlay_properties(parts, overlay)
|
|
608
|
+
|
|
609
|
+
parts << "l-end"
|
|
610
|
+
parts.join(",")
|
|
611
|
+
end
|
|
612
|
+
|
|
613
|
+
# Safe property access for model objects and hashes
|
|
614
|
+
def safe_get(obj, key)
|
|
615
|
+
return nil unless obj
|
|
616
|
+
|
|
617
|
+
# Support both BaseModel objects and plain hashes
|
|
618
|
+
if obj.is_a?(Hash)
|
|
619
|
+
obj[key.to_sym] || obj[key.to_s]
|
|
620
|
+
elsif obj.respond_to?(key.to_sym)
|
|
621
|
+
obj.send(key.to_sym)
|
|
622
|
+
else
|
|
623
|
+
nil
|
|
624
|
+
end
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
# Add overlay properties like position, timing, transformations (matching Node.js)
|
|
628
|
+
def add_overlay_properties(parts, overlay)
|
|
629
|
+
# Add position properties
|
|
630
|
+
position = safe_get(overlay, :position)
|
|
631
|
+
if position
|
|
632
|
+
x = safe_get(position, :x)
|
|
633
|
+
y = safe_get(position, :y_)
|
|
634
|
+
focus = safe_get(position, :focus)
|
|
635
|
+
|
|
636
|
+
parts << "lx-#{x}" if x
|
|
637
|
+
parts << "ly-#{y}" if y
|
|
638
|
+
parts << "lfo-#{focus}" if focus
|
|
639
|
+
end
|
|
640
|
+
|
|
641
|
+
# Add timing properties
|
|
642
|
+
timing = safe_get(overlay, :timing)
|
|
643
|
+
if timing
|
|
644
|
+
start = safe_get(timing, :start)
|
|
645
|
+
end_time = safe_get(timing, :end_)
|
|
646
|
+
duration = safe_get(timing, :duration)
|
|
647
|
+
|
|
648
|
+
parts << "lso-#{start.to_i}" if start
|
|
649
|
+
parts << "leo-#{end_time.to_i}" if end_time
|
|
650
|
+
parts << "ldu-#{duration}" if duration
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
# Add transformation properties
|
|
654
|
+
transformations = safe_get(overlay, :transformation)
|
|
655
|
+
return unless transformations && transformations.is_a?(Array)
|
|
656
|
+
transformation_string = build_transformation_string(transformations)
|
|
657
|
+
return unless transformation_string && !transformation_string.strip.empty?
|
|
658
|
+
parts << transformation_string
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
# Calculate expiry timestamp for URL signing
|
|
662
|
+
def get_signature_timestamp(seconds)
|
|
663
|
+
return DEFAULT_TIMESTAMP unless seconds && seconds.to_i.positive?
|
|
664
|
+
|
|
665
|
+
sec = seconds.to_i
|
|
666
|
+
return DEFAULT_TIMESTAMP if sec <= 0
|
|
667
|
+
|
|
668
|
+
Time.now.to_i + sec
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
# Generate HMAC-SHA1 signature for URL signing
|
|
672
|
+
def get_signature(private_key:, url:, url_endpoint:, expiry_timestamp:)
|
|
673
|
+
return "" if private_key.nil? || private_key.empty? || url.nil? || url.empty? || url_endpoint.nil?
|
|
674
|
+
|
|
675
|
+
# Create string to sign: relative path + expiry timestamp
|
|
676
|
+
endpoint_with_slash = add_trailing_slash(url_endpoint)
|
|
677
|
+
string_to_sign = url.gsub(endpoint_with_slash, "") + expiry_timestamp.to_s
|
|
678
|
+
|
|
679
|
+
Imagekitio::CryptoUtils.create_hmac_sha1(private_key, string_to_sign)
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
# Add trailing slash to string if not present
|
|
683
|
+
def add_trailing_slash(str)
|
|
684
|
+
return str unless str.is_a?(String)
|
|
685
|
+
return str if str.end_with?("/")
|
|
686
|
+
"#{str}/"
|
|
687
|
+
end
|
|
688
|
+
end
|
|
689
|
+
end
|