uploadcare-ruby 4.4.3 → 5.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/.env.example +7 -0
- data/.github/workflows/gem-push.yml +1 -1
- data/.github/workflows/ruby.yml +10 -13
- data/.gitignore +9 -0
- data/.rubocop.yml +95 -8
- data/CHANGELOG.md +80 -1
- data/Gemfile +23 -6
- data/MIGRATING_V5.md +290 -0
- data/README.md +422 -671
- data/Rakefile +5 -1
- data/api_examples/README.md +77 -0
- data/api_examples/rest_api/delete_files_storage.rb +3 -5
- data/api_examples/rest_api/delete_files_uuid_metadata_key.rb +3 -4
- data/api_examples/rest_api/delete_files_uuid_storage.rb +3 -4
- data/api_examples/rest_api/delete_groups_uuid.rb +3 -4
- data/api_examples/rest_api/delete_webhooks_unsubscribe.rb +3 -4
- data/api_examples/rest_api/get_addons_aws_rekognition_detect_labels_execute_status.rb +3 -6
- data/api_examples/rest_api/get_addons_aws_rekognition_detect_moderation_labels_execute_status.rb +3 -6
- data/api_examples/rest_api/get_addons_remove_bg_execute_status.rb +3 -6
- data/api_examples/rest_api/get_addons_uc_clamav_virus_scan_execute_status.rb +3 -6
- data/api_examples/rest_api/get_convert_document_status_token.rb +3 -5
- data/api_examples/rest_api/get_convert_document_uuid.rb +3 -5
- data/api_examples/rest_api/get_convert_video_status_token.rb +3 -5
- data/api_examples/rest_api/get_files.rb +3 -5
- data/api_examples/rest_api/get_files_uuid.rb +3 -5
- data/api_examples/rest_api/get_files_uuid_metadata.rb +3 -5
- data/api_examples/rest_api/get_files_uuid_metadata_key.rb +3 -5
- data/api_examples/rest_api/get_groups.rb +3 -5
- data/api_examples/rest_api/get_groups_uuid.rb +3 -5
- data/api_examples/rest_api/get_project.rb +3 -5
- data/api_examples/rest_api/get_webhooks.rb +3 -5
- data/api_examples/rest_api/post_addons_aws_rekognition_detect_labels_execute.rb +3 -5
- data/api_examples/rest_api/post_addons_aws_rekognition_detect_moderation_labels_execute.rb +3 -5
- data/api_examples/rest_api/post_addons_remove_bg_execute.rb +3 -5
- data/api_examples/rest_api/post_addons_uc_clamav_virus_scan_execute.rb +3 -5
- data/api_examples/rest_api/post_convert_document.rb +3 -8
- data/api_examples/rest_api/post_convert_video.rb +3 -10
- data/api_examples/rest_api/post_files_local_copy.rb +3 -6
- data/api_examples/rest_api/post_files_remote_copy.rb +3 -7
- data/api_examples/rest_api/post_webhooks.rb +3 -9
- data/api_examples/rest_api/put_files_storage.rb +3 -8
- data/api_examples/rest_api/put_files_uuid_metadata_key.rb +3 -7
- data/api_examples/rest_api/put_files_uuid_storage.rb +3 -5
- data/api_examples/rest_api/put_webhooks_id.rb +3 -11
- data/api_examples/support/example_helper.rb +250 -0
- data/api_examples/support/run_rest_example.rb +161 -0
- data/api_examples/support/run_upload_example.rb +88 -0
- data/api_examples/upload_api/get_from_url_status.rb +3 -5
- data/api_examples/upload_api/get_group_info.rb +3 -6
- data/api_examples/upload_api/get_info.rb +3 -6
- data/api_examples/upload_api/post_base.rb +3 -5
- data/api_examples/upload_api/post_from_url.rb +3 -5
- data/api_examples/upload_api/post_group.rb +3 -8
- data/api_examples/upload_api/post_multipart_complete.rb +3 -7
- data/api_examples/upload_api/post_multipart_start.rb +3 -7
- data/api_examples/upload_api/put_multipart_part.rb +4 -0
- data/bin/console +1 -1
- data/context7.json +74 -0
- data/docs/release-notes-5.0.0.md +47 -0
- data/examples/README.md +39 -0
- data/examples/batch_upload.rb +54 -0
- data/examples/group_creation.rb +88 -0
- data/examples/large_file_upload.rb +88 -0
- data/examples/simple_upload.rb +39 -0
- data/examples/upload_with_progress.rb +84 -0
- data/examples/url_upload.rb +56 -0
- data/lib/uploadcare/api/rest/addons.rb +107 -0
- data/lib/uploadcare/api/rest/document_conversions.rb +65 -0
- data/lib/uploadcare/api/rest/file_metadata.rb +71 -0
- data/lib/uploadcare/api/rest/files.rb +112 -0
- data/lib/uploadcare/api/rest/groups.rb +49 -0
- data/lib/uploadcare/api/rest/project.rb +23 -0
- data/lib/uploadcare/api/rest/video_conversions.rb +52 -0
- data/lib/uploadcare/api/rest/webhooks.rb +74 -0
- data/lib/uploadcare/api/rest.rb +254 -0
- data/lib/uploadcare/api/upload/files.rb +313 -0
- data/lib/uploadcare/api/upload/groups.rb +72 -0
- data/lib/uploadcare/api/upload.rb +272 -0
- data/lib/uploadcare/client/addons_accessor.rb +85 -0
- data/lib/uploadcare/client/api.rb +33 -0
- data/lib/uploadcare/client/conversions_accessor.rb +33 -0
- data/lib/uploadcare/client/document_conversions_accessor.rb +41 -0
- data/lib/uploadcare/client/file_metadata_accessor.rb +46 -0
- data/lib/uploadcare/client/files_accessor.rb +82 -0
- data/lib/uploadcare/client/groups_accessor.rb +35 -0
- data/lib/uploadcare/client/project_accessor.rb +17 -0
- data/lib/uploadcare/client/video_conversions_accessor.rb +33 -0
- data/lib/uploadcare/client/webhooks_accessor.rb +42 -0
- data/lib/uploadcare/client.rb +127 -0
- data/lib/uploadcare/cname_generator.rb +68 -0
- data/lib/uploadcare/collections/batch_result.rb +35 -0
- data/lib/uploadcare/collections/paginated.rb +165 -0
- data/lib/uploadcare/configuration.rb +81 -0
- data/lib/uploadcare/exception/auth_error.rb +2 -6
- data/lib/uploadcare/exception/configuration_error.rb +4 -0
- data/lib/uploadcare/exception/conversion_error.rb +2 -6
- data/lib/uploadcare/exception/invalid_request_error.rb +4 -0
- data/lib/uploadcare/exception/multipart_upload_error.rb +4 -0
- data/lib/uploadcare/exception/not_found_error.rb +4 -0
- data/lib/uploadcare/exception/request_error.rb +2 -6
- data/lib/uploadcare/exception/retry_error.rb +2 -6
- data/lib/uploadcare/exception/throttle_error.rb +7 -11
- data/lib/uploadcare/exception/unknown_status_error.rb +4 -0
- data/lib/uploadcare/exception/upload_error.rb +4 -0
- data/lib/uploadcare/exception/upload_timeout_error.rb +4 -0
- data/lib/uploadcare/internal/authenticator.rb +101 -0
- data/lib/uploadcare/internal/error_handler.rb +102 -0
- data/lib/uploadcare/internal/signature_generator.rb +31 -0
- data/lib/uploadcare/internal/throttle_handler.rb +36 -0
- data/lib/uploadcare/internal/upload_io.rb +110 -0
- data/lib/uploadcare/internal/upload_params_generator.rb +86 -0
- data/lib/uploadcare/internal/user_agent.rb +22 -0
- data/lib/uploadcare/operations/multipart_upload.rb +213 -0
- data/lib/uploadcare/operations/upload_router.rb +162 -0
- data/lib/uploadcare/resources/addon_execution.rb +97 -0
- data/lib/uploadcare/resources/base_resource.rb +61 -0
- data/lib/uploadcare/resources/document_conversion.rb +81 -0
- data/lib/uploadcare/resources/file.rb +366 -0
- data/lib/uploadcare/resources/file_metadata.rb +135 -0
- data/lib/uploadcare/resources/group.rb +142 -0
- data/lib/uploadcare/resources/project.rb +26 -0
- data/lib/uploadcare/resources/video_conversion.rb +59 -0
- data/lib/uploadcare/resources/webhook.rb +85 -0
- data/lib/uploadcare/result.rb +85 -0
- data/lib/uploadcare/signed_url_generators/akamai_generator.rb +50 -51
- data/lib/uploadcare/signed_url_generators/base_generator.rb +15 -15
- data/lib/uploadcare/version.rb +7 -0
- data/lib/uploadcare/webhook_signature_verifier.rb +60 -0
- data/lib/uploadcare.rb +84 -50
- data/mise.toml +2 -0
- data/uploadcare-ruby.gemspec +8 -7
- metadata +103 -74
- data/api_examples/upload_api/put_presigned_url_x.rb +0 -8
- data/lib/uploadcare/api/api.rb +0 -25
- data/lib/uploadcare/client/addons_client.rb +0 -69
- data/lib/uploadcare/client/conversion/base_conversion_client.rb +0 -60
- data/lib/uploadcare/client/conversion/document_conversion_client.rb +0 -45
- data/lib/uploadcare/client/conversion/video_conversion_client.rb +0 -46
- data/lib/uploadcare/client/file_client.rb +0 -48
- data/lib/uploadcare/client/file_list_client.rb +0 -46
- data/lib/uploadcare/client/file_metadata_client.rb +0 -36
- data/lib/uploadcare/client/group_client.rb +0 -45
- data/lib/uploadcare/client/multipart_upload/chunks_client.rb +0 -58
- data/lib/uploadcare/client/multipart_upload_client.rb +0 -64
- data/lib/uploadcare/client/project_client.rb +0 -20
- data/lib/uploadcare/client/rest_client.rb +0 -77
- data/lib/uploadcare/client/rest_group_client.rb +0 -43
- data/lib/uploadcare/client/upload_client.rb +0 -46
- data/lib/uploadcare/client/uploader_client.rb +0 -128
- data/lib/uploadcare/client/webhook_client.rb +0 -49
- data/lib/uploadcare/concern/error_handler.rb +0 -54
- data/lib/uploadcare/concern/throttle_handler.rb +0 -25
- data/lib/uploadcare/concern/upload_error_handler.rb +0 -32
- data/lib/uploadcare/entity/addons.rb +0 -14
- data/lib/uploadcare/entity/conversion/base_converter.rb +0 -43
- data/lib/uploadcare/entity/conversion/document_converter.rb +0 -15
- data/lib/uploadcare/entity/conversion/video_converter.rb +0 -15
- data/lib/uploadcare/entity/decorator/paginator.rb +0 -79
- data/lib/uploadcare/entity/entity.rb +0 -18
- data/lib/uploadcare/entity/file.rb +0 -103
- data/lib/uploadcare/entity/file_list.rb +0 -32
- data/lib/uploadcare/entity/file_metadata.rb +0 -30
- data/lib/uploadcare/entity/group.rb +0 -49
- data/lib/uploadcare/entity/group_list.rb +0 -24
- data/lib/uploadcare/entity/project.rb +0 -13
- data/lib/uploadcare/entity/uploader.rb +0 -93
- data/lib/uploadcare/entity/webhook.rb +0 -14
- data/lib/uploadcare/param/authentication_header.rb +0 -37
- data/lib/uploadcare/param/conversion/document/processing_job_url_builder.rb +0 -39
- data/lib/uploadcare/param/conversion/video/processing_job_url_builder.rb +0 -64
- data/lib/uploadcare/param/param.rb +0 -10
- data/lib/uploadcare/param/secure_auth_header.rb +0 -51
- data/lib/uploadcare/param/simple_auth_header.rb +0 -14
- data/lib/uploadcare/param/upload/signature_generator.rb +0 -24
- data/lib/uploadcare/param/upload/upload_params_generator.rb +0 -41
- data/lib/uploadcare/param/user_agent.rb +0 -21
- data/lib/uploadcare/param/webhook_signature_verifier.rb +0 -23
- data/lib/uploadcare/ruby/version.rb +0 -5
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'dotenv/load'
|
|
5
|
+
require 'tempfile'
|
|
6
|
+
require 'securerandom'
|
|
7
|
+
|
|
8
|
+
require_relative '../../lib/uploadcare'
|
|
9
|
+
|
|
10
|
+
module ApiExamples
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
module ApiExamples::ExampleHelper
|
|
14
|
+
SAMPLE_IMAGE_URL = 'https://upload.wikimedia.org/wikipedia/commons/3/3f/JPEG_example_flower.jpg'
|
|
15
|
+
SAMPLE_VIDEO_URL = 'https://samplelib.com/lib/preview/mp4/sample-5s.mp4'
|
|
16
|
+
|
|
17
|
+
module_function
|
|
18
|
+
|
|
19
|
+
def client
|
|
20
|
+
@client ||= Uploadcare::Client.new(
|
|
21
|
+
public_key: ENV.fetch('UPLOADCARE_PUBLIC_KEY'),
|
|
22
|
+
secret_key: ENV.fetch('UPLOADCARE_SECRET_KEY'),
|
|
23
|
+
auth_type: ENV.fetch('UPLOADCARE_AUTH_TYPE', 'Uploadcare.Simple')
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def run
|
|
28
|
+
output(yield(client))
|
|
29
|
+
rescue StandardError => e
|
|
30
|
+
warn("#{e.class}: #{e.message}")
|
|
31
|
+
exit 1
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def output(value)
|
|
35
|
+
puts JSON.pretty_generate(value)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def unwrap(result)
|
|
39
|
+
Uploadcare::Result.unwrap(result)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def skip(message)
|
|
43
|
+
output('skipped' => true, 'reason' => message)
|
|
44
|
+
exit 0
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def fixture_path(name)
|
|
48
|
+
File.expand_path("../../spec/fixtures/#{name}", __dir__)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def with_uploaded_file(path: fixture_path('kitten.jpeg'), store: true, metadata: {})
|
|
52
|
+
handle = File.open(path, 'rb')
|
|
53
|
+
file = client.files.upload(handle, store: store, metadata: metadata)
|
|
54
|
+
yield file
|
|
55
|
+
ensure
|
|
56
|
+
handle&.close
|
|
57
|
+
safe_delete_file(file)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def with_uploaded_files(paths: [fixture_path('kitten.jpeg'), fixture_path('another_kitten.jpeg')], store: true)
|
|
61
|
+
handles = paths.map { |path| File.open(path, 'rb') }
|
|
62
|
+
files = client.files.upload(handles, store: store)
|
|
63
|
+
yield files
|
|
64
|
+
ensure
|
|
65
|
+
handles&.each(&:close)
|
|
66
|
+
Array(files).each { |file| safe_delete_file(file) }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def with_fixture_file(name)
|
|
70
|
+
handle = File.open(fixture_path(name), 'rb')
|
|
71
|
+
response = yield handle
|
|
72
|
+
response
|
|
73
|
+
ensure
|
|
74
|
+
handle&.close
|
|
75
|
+
safe_delete_file(uploaded_uuid_from_base_response(response)) if response
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def with_uploaded_group
|
|
79
|
+
with_uploaded_files do |files|
|
|
80
|
+
group = client.groups.create(uuids: files.map(&:uuid))
|
|
81
|
+
yield group, files
|
|
82
|
+
ensure
|
|
83
|
+
safe_delete_group(group)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def with_webhook
|
|
88
|
+
webhook = client.webhooks.create(
|
|
89
|
+
target_url: "https://example.com/uploadcare-webhook/#{SecureRandom.hex(4)}",
|
|
90
|
+
is_active: true
|
|
91
|
+
)
|
|
92
|
+
yield webhook
|
|
93
|
+
ensure
|
|
94
|
+
safe_delete_webhook(webhook)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def with_uploaded_pdf
|
|
98
|
+
pdf = Tempfile.new(['uploadcare-example', '.pdf'])
|
|
99
|
+
pdf.write(minimal_pdf)
|
|
100
|
+
pdf.rewind
|
|
101
|
+
file = client.files.upload(pdf, store: true)
|
|
102
|
+
yield file
|
|
103
|
+
ensure
|
|
104
|
+
pdf&.close!
|
|
105
|
+
safe_delete_file(file)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def with_uploaded_video
|
|
109
|
+
file = client.files.upload_from_url(SAMPLE_VIDEO_URL, store: true)
|
|
110
|
+
yield file
|
|
111
|
+
ensure
|
|
112
|
+
safe_delete_file(file)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def multipart_part_size
|
|
116
|
+
5 * 1024 * 1024
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def with_multipart_session
|
|
120
|
+
file = File.open(fixture_path('big.jpeg'), 'rb')
|
|
121
|
+
response = unwrap(
|
|
122
|
+
client.api.upload.files.multipart_start(
|
|
123
|
+
filename: File.basename(file.path),
|
|
124
|
+
size: file.size,
|
|
125
|
+
content_type: 'image/jpeg',
|
|
126
|
+
part_size: multipart_part_size,
|
|
127
|
+
store: true
|
|
128
|
+
)
|
|
129
|
+
)
|
|
130
|
+
yield file, response
|
|
131
|
+
ensure
|
|
132
|
+
file&.close
|
|
133
|
+
safe_delete_file(response['completed_uuid']) if response.is_a?(Hash) && response['completed_uuid']
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def upload_multipart_part(file:, session:, index:)
|
|
137
|
+
file.seek(index * multipart_part_size)
|
|
138
|
+
data = file.read(multipart_part_size)
|
|
139
|
+
return nil unless data && !data.empty?
|
|
140
|
+
|
|
141
|
+
client.api.upload.upload_part_to_url(session.fetch('parts').fetch(index), data)
|
|
142
|
+
data.bytesize
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def finish_multipart_upload(file:, session:, skip_indices: [])
|
|
146
|
+
session.fetch('parts').each_index do |index|
|
|
147
|
+
next if skip_indices.include?(index)
|
|
148
|
+
|
|
149
|
+
upload_multipart_part(file: file, session: session, index: index)
|
|
150
|
+
end
|
|
151
|
+
result = unwrap(client.api.upload.files.multipart_complete(uuid: session.fetch('uuid')))
|
|
152
|
+
session['completed_uuid'] = result['uuid']
|
|
153
|
+
result
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def uploaded_uuid_from_base_response(response)
|
|
157
|
+
response.values.first
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def conversion_token(response)
|
|
161
|
+
result = if response.respond_to?(:result)
|
|
162
|
+
response.result
|
|
163
|
+
else
|
|
164
|
+
response.fetch('result')
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
Array(result).first.fetch('token')
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def safe_delete_file(file)
|
|
171
|
+
return unless file
|
|
172
|
+
|
|
173
|
+
uuid = if file.respond_to?(:uuid)
|
|
174
|
+
file.uuid
|
|
175
|
+
elsif file.is_a?(Hash)
|
|
176
|
+
file['uuid'] || file[:uuid]
|
|
177
|
+
else
|
|
178
|
+
file
|
|
179
|
+
end
|
|
180
|
+
return if uuid.to_s.empty?
|
|
181
|
+
|
|
182
|
+
client.api.rest.files.delete(uuid: uuid)
|
|
183
|
+
rescue StandardError
|
|
184
|
+
nil
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def safe_delete_group(group)
|
|
188
|
+
group_id = if group.respond_to?(:id)
|
|
189
|
+
group.id
|
|
190
|
+
elsif group.is_a?(Hash)
|
|
191
|
+
group['id'] || group[:id]
|
|
192
|
+
else
|
|
193
|
+
group
|
|
194
|
+
end
|
|
195
|
+
return if group_id.to_s.empty?
|
|
196
|
+
|
|
197
|
+
client.api.rest.groups.delete(uuid: group_id)
|
|
198
|
+
rescue StandardError
|
|
199
|
+
nil
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def safe_delete_webhook(webhook)
|
|
203
|
+
return unless webhook&.target_url
|
|
204
|
+
|
|
205
|
+
client.api.rest.webhooks.delete(target_url: webhook.target_url)
|
|
206
|
+
rescue StandardError
|
|
207
|
+
nil
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def minimal_pdf
|
|
211
|
+
<<~PDF
|
|
212
|
+
%PDF-1.4
|
|
213
|
+
1 0 obj
|
|
214
|
+
<< /Type /Catalog /Pages 2 0 R >>
|
|
215
|
+
endobj
|
|
216
|
+
2 0 obj
|
|
217
|
+
<< /Type /Pages /Kids [3 0 R] /Count 1 >>
|
|
218
|
+
endobj
|
|
219
|
+
3 0 obj
|
|
220
|
+
<< /Type /Page /Parent 2 0 R /MediaBox [0 0 300 144] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >>
|
|
221
|
+
endobj
|
|
222
|
+
4 0 obj
|
|
223
|
+
<< /Length 44 >>
|
|
224
|
+
stream
|
|
225
|
+
BT
|
|
226
|
+
/F1 18 Tf
|
|
227
|
+
72 100 Td
|
|
228
|
+
(Uploadcare PDF) Tj
|
|
229
|
+
ET
|
|
230
|
+
endstream
|
|
231
|
+
endobj
|
|
232
|
+
5 0 obj
|
|
233
|
+
<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>
|
|
234
|
+
endobj
|
|
235
|
+
xref
|
|
236
|
+
0 6
|
|
237
|
+
0000000000 65535 f
|
|
238
|
+
0000000009 00000 n
|
|
239
|
+
0000000058 00000 n
|
|
240
|
+
0000000115 00000 n
|
|
241
|
+
0000000241 00000 n
|
|
242
|
+
0000000334 00000 n
|
|
243
|
+
trailer
|
|
244
|
+
<< /Size 6 /Root 1 0 R >>
|
|
245
|
+
startxref
|
|
246
|
+
404
|
|
247
|
+
%%EOF
|
|
248
|
+
PDF
|
|
249
|
+
end
|
|
250
|
+
end
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'example_helper'
|
|
4
|
+
|
|
5
|
+
module ApiExamples::RunRestExample
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
ApiExamples::ExampleHelper.run do |client|
|
|
10
|
+
case File.basename($PROGRAM_NAME)
|
|
11
|
+
when 'get_project.rb'
|
|
12
|
+
client.project.current
|
|
13
|
+
when 'get_files.rb'
|
|
14
|
+
client.files.list(limit: 2)
|
|
15
|
+
when 'get_files_uuid.rb'
|
|
16
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
17
|
+
client.files.find(uuid: file.uuid)
|
|
18
|
+
end
|
|
19
|
+
when 'put_files_uuid_storage.rb'
|
|
20
|
+
ApiExamples::ExampleHelper.with_uploaded_file(store: false, &:store)
|
|
21
|
+
when 'delete_files_uuid_storage.rb'
|
|
22
|
+
ApiExamples::ExampleHelper.with_uploaded_file(&:delete)
|
|
23
|
+
when 'put_files_storage.rb'
|
|
24
|
+
ApiExamples::ExampleHelper.with_uploaded_files(store: false) do |files|
|
|
25
|
+
client.files.batch_store(uuids: files.map(&:uuid))
|
|
26
|
+
end
|
|
27
|
+
when 'delete_files_storage.rb'
|
|
28
|
+
ApiExamples::ExampleHelper.with_uploaded_files do |files|
|
|
29
|
+
client.files.batch_delete(uuids: files.map(&:uuid))
|
|
30
|
+
end
|
|
31
|
+
when 'post_files_local_copy.rb'
|
|
32
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
33
|
+
copied = client.files.copy_to_local(source: file.uuid, options: { store: true })
|
|
34
|
+
copied
|
|
35
|
+
ensure
|
|
36
|
+
ApiExamples::ExampleHelper.safe_delete_file(copied)
|
|
37
|
+
end
|
|
38
|
+
when 'post_files_remote_copy.rb'
|
|
39
|
+
target = ENV.fetch('UPLOADCARE_REMOTE_STORAGE', nil)
|
|
40
|
+
if target.to_s.empty?
|
|
41
|
+
ApiExamples::ExampleHelper.skip('Set UPLOADCARE_REMOTE_STORAGE to a configured custom storage name.')
|
|
42
|
+
end
|
|
43
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
44
|
+
client.files.copy_to_remote(source: file.uuid, target: target)
|
|
45
|
+
end
|
|
46
|
+
when 'get_groups.rb'
|
|
47
|
+
client.groups.list(limit: 2)
|
|
48
|
+
when 'get_groups_uuid.rb'
|
|
49
|
+
ApiExamples::ExampleHelper.with_uploaded_group do |group, _files|
|
|
50
|
+
client.groups.find(group_id: group.id)
|
|
51
|
+
end
|
|
52
|
+
when 'delete_groups_uuid.rb'
|
|
53
|
+
ApiExamples::ExampleHelper.with_uploaded_group do |group, _files|
|
|
54
|
+
group.delete
|
|
55
|
+
end
|
|
56
|
+
when 'get_webhooks.rb'
|
|
57
|
+
client.webhooks.list
|
|
58
|
+
when 'post_webhooks.rb'
|
|
59
|
+
ApiExamples::ExampleHelper.with_webhook do |webhook|
|
|
60
|
+
{
|
|
61
|
+
'id' => webhook.id,
|
|
62
|
+
'target_url' => webhook.target_url,
|
|
63
|
+
'is_active' => webhook.is_active,
|
|
64
|
+
'event' => webhook.event
|
|
65
|
+
}
|
|
66
|
+
end
|
|
67
|
+
when 'put_webhooks_id.rb'
|
|
68
|
+
ApiExamples::ExampleHelper.with_webhook do |webhook|
|
|
69
|
+
client.webhooks.update(id: webhook.id, is_active: false)
|
|
70
|
+
end
|
|
71
|
+
when 'delete_webhooks_unsubscribe.rb'
|
|
72
|
+
ApiExamples::ExampleHelper.with_webhook do |webhook|
|
|
73
|
+
client.webhooks.delete(target_url: webhook.target_url)
|
|
74
|
+
{ 'target_url' => webhook.target_url, 'deleted' => true }
|
|
75
|
+
end
|
|
76
|
+
when 'get_files_uuid_metadata.rb'
|
|
77
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
78
|
+
client.file_metadata.update(uuid: file.uuid, key: 'color', value: 'orange')
|
|
79
|
+
client.file_metadata.index(uuid: file.uuid)
|
|
80
|
+
end
|
|
81
|
+
when 'get_files_uuid_metadata_key.rb'
|
|
82
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
83
|
+
client.file_metadata.update(uuid: file.uuid, key: 'color', value: 'orange')
|
|
84
|
+
client.file_metadata.show(uuid: file.uuid, key: 'color')
|
|
85
|
+
end
|
|
86
|
+
when 'put_files_uuid_metadata_key.rb'
|
|
87
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
88
|
+
client.file_metadata.update(uuid: file.uuid, key: 'color', value: 'orange')
|
|
89
|
+
end
|
|
90
|
+
when 'delete_files_uuid_metadata_key.rb'
|
|
91
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
92
|
+
client.file_metadata.update(uuid: file.uuid, key: 'color', value: 'orange')
|
|
93
|
+
client.file_metadata.delete(uuid: file.uuid, key: 'color')
|
|
94
|
+
{ 'uuid' => file.uuid, 'key' => 'color', 'deleted' => true }
|
|
95
|
+
end
|
|
96
|
+
when 'post_addons_aws_rekognition_detect_labels_execute.rb'
|
|
97
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
98
|
+
client.addons.aws_rekognition_detect_labels(uuid: file.uuid)
|
|
99
|
+
end
|
|
100
|
+
when 'get_addons_aws_rekognition_detect_labels_execute_status.rb'
|
|
101
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
102
|
+
response = client.addons.aws_rekognition_detect_labels(uuid: file.uuid)
|
|
103
|
+
client.addons.aws_rekognition_detect_labels_status(request_id: response.request_id)
|
|
104
|
+
end
|
|
105
|
+
when 'post_addons_aws_rekognition_detect_moderation_labels_execute.rb'
|
|
106
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
107
|
+
client.addons.aws_rekognition_detect_moderation_labels(uuid: file.uuid)
|
|
108
|
+
end
|
|
109
|
+
when 'get_addons_aws_rekognition_detect_moderation_labels_execute_status.rb'
|
|
110
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
111
|
+
response = client.addons.aws_rekognition_detect_moderation_labels(uuid: file.uuid)
|
|
112
|
+
client.addons.aws_rekognition_detect_moderation_labels_status(request_id: response.request_id)
|
|
113
|
+
end
|
|
114
|
+
when 'post_addons_uc_clamav_virus_scan_execute.rb'
|
|
115
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
116
|
+
client.addons.uc_clamav_virus_scan(uuid: file.uuid)
|
|
117
|
+
end
|
|
118
|
+
when 'get_addons_uc_clamav_virus_scan_execute_status.rb'
|
|
119
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
120
|
+
response = client.addons.uc_clamav_virus_scan(uuid: file.uuid)
|
|
121
|
+
client.addons.uc_clamav_virus_scan_status(request_id: response.request_id)
|
|
122
|
+
end
|
|
123
|
+
when 'post_addons_remove_bg_execute.rb'
|
|
124
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
125
|
+
client.addons.remove_bg(uuid: file.uuid)
|
|
126
|
+
end
|
|
127
|
+
when 'get_addons_remove_bg_execute_status.rb'
|
|
128
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
129
|
+
response = client.addons.remove_bg(uuid: file.uuid)
|
|
130
|
+
client.addons.remove_bg_status(request_id: response.request_id)
|
|
131
|
+
end
|
|
132
|
+
when 'get_convert_document_uuid.rb'
|
|
133
|
+
ApiExamples::ExampleHelper.with_uploaded_pdf do |file|
|
|
134
|
+
client.conversions.documents.info(uuid: file.uuid)
|
|
135
|
+
end
|
|
136
|
+
when 'post_convert_document.rb'
|
|
137
|
+
ApiExamples::ExampleHelper.with_uploaded_pdf do |file|
|
|
138
|
+
client.conversions.documents.convert(uuid: file.uuid, format: :jpg)
|
|
139
|
+
end
|
|
140
|
+
when 'get_convert_document_status_token.rb'
|
|
141
|
+
ApiExamples::ExampleHelper.with_uploaded_pdf do |file|
|
|
142
|
+
response = client.conversions.documents.convert(uuid: file.uuid, format: :jpg)
|
|
143
|
+
client.conversions.documents.status(token: ApiExamples::ExampleHelper.conversion_token(response))
|
|
144
|
+
end
|
|
145
|
+
when 'post_convert_video.rb'
|
|
146
|
+
ApiExamples::ExampleHelper.with_uploaded_video do |file|
|
|
147
|
+
client.conversions.videos.convert(uuid: file.uuid, format: :webm, quality: :normal)
|
|
148
|
+
end
|
|
149
|
+
when 'get_convert_video_status_token.rb'
|
|
150
|
+
ApiExamples::ExampleHelper.with_uploaded_video do |file|
|
|
151
|
+
response = client.conversions.videos.convert(uuid: file.uuid, format: :webm, quality: :normal)
|
|
152
|
+
client.conversions.videos.status(token: ApiExamples::ExampleHelper.conversion_token(response))
|
|
153
|
+
end
|
|
154
|
+
else
|
|
155
|
+
raise "No REST API example mapped for #{File.basename($PROGRAM_NAME)}"
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
ApiExamples::RunRestExample.call
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'example_helper'
|
|
4
|
+
|
|
5
|
+
module ApiExamples::RunUploadExample
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def call
|
|
9
|
+
ApiExamples::ExampleHelper.run do |client|
|
|
10
|
+
case File.basename($PROGRAM_NAME)
|
|
11
|
+
when 'post_base.rb'
|
|
12
|
+
run_base_upload(client)
|
|
13
|
+
when 'post_from_url.rb'
|
|
14
|
+
run_url_upload(client)
|
|
15
|
+
when 'get_from_url_status.rb'
|
|
16
|
+
response = ApiExamples::ExampleHelper.unwrap(
|
|
17
|
+
client.api.upload.files.from_url(
|
|
18
|
+
source_url: ApiExamples::ExampleHelper::SAMPLE_IMAGE_URL,
|
|
19
|
+
async: true,
|
|
20
|
+
store: true
|
|
21
|
+
)
|
|
22
|
+
)
|
|
23
|
+
ApiExamples::ExampleHelper.unwrap(client.api.upload.files.from_url_status(token: response.fetch('token')))
|
|
24
|
+
when 'get_info.rb'
|
|
25
|
+
ApiExamples::ExampleHelper.with_uploaded_file do |file|
|
|
26
|
+
ApiExamples::ExampleHelper.unwrap(client.api.upload.files.info(file_id: file.uuid))
|
|
27
|
+
end
|
|
28
|
+
when 'post_group.rb'
|
|
29
|
+
ApiExamples::ExampleHelper.with_uploaded_files do |files|
|
|
30
|
+
group = ApiExamples::ExampleHelper.unwrap(client.api.upload.groups.create(files: files.map(&:uuid)))
|
|
31
|
+
group
|
|
32
|
+
ensure
|
|
33
|
+
ApiExamples::ExampleHelper.safe_delete_group(group)
|
|
34
|
+
end
|
|
35
|
+
when 'get_group_info.rb'
|
|
36
|
+
ApiExamples::ExampleHelper.with_uploaded_group do |group, _files|
|
|
37
|
+
ApiExamples::ExampleHelper.unwrap(client.api.upload.groups.info(group_id: group.id))
|
|
38
|
+
end
|
|
39
|
+
when 'post_multipart_start.rb'
|
|
40
|
+
ApiExamples::ExampleHelper.with_multipart_session do |file, session|
|
|
41
|
+
completed_file = ApiExamples::ExampleHelper.finish_multipart_upload(file: file, session: session)
|
|
42
|
+
{
|
|
43
|
+
'uuid' => session.fetch('uuid'),
|
|
44
|
+
'parts' => session.fetch('parts').length,
|
|
45
|
+
'completed_file' => completed_file.fetch('uuid')
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
when 'put_multipart_part.rb'
|
|
49
|
+
ApiExamples::ExampleHelper.with_multipart_session do |file, session|
|
|
50
|
+
uploaded = ApiExamples::ExampleHelper.upload_multipart_part(file: file, session: session, index: 0)
|
|
51
|
+
completed = ApiExamples::ExampleHelper.finish_multipart_upload(
|
|
52
|
+
file: file,
|
|
53
|
+
session: session,
|
|
54
|
+
skip_indices: [0]
|
|
55
|
+
)
|
|
56
|
+
{
|
|
57
|
+
'uuid' => session.fetch('uuid'),
|
|
58
|
+
'uploaded_bytes' => uploaded,
|
|
59
|
+
'completed_file' => completed.fetch('uuid')
|
|
60
|
+
}
|
|
61
|
+
end
|
|
62
|
+
when 'post_multipart_complete.rb'
|
|
63
|
+
ApiExamples::ExampleHelper.with_multipart_session do |file, session|
|
|
64
|
+
ApiExamples::ExampleHelper.finish_multipart_upload(file: file, session: session)
|
|
65
|
+
end
|
|
66
|
+
else
|
|
67
|
+
raise "No Upload API example mapped for #{File.basename($PROGRAM_NAME)}"
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def run_base_upload(client)
|
|
73
|
+
ApiExamples::ExampleHelper.with_fixture_file('kitten.jpeg') do |handle|
|
|
74
|
+
ApiExamples::ExampleHelper.unwrap(client.api.upload.files.direct(file: handle, store: true))
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def run_url_upload(client)
|
|
79
|
+
response = ApiExamples::ExampleHelper.unwrap(
|
|
80
|
+
client.api.upload.files.from_url(source_url: ApiExamples::ExampleHelper::SAMPLE_IMAGE_URL, store: true)
|
|
81
|
+
)
|
|
82
|
+
response
|
|
83
|
+
ensure
|
|
84
|
+
ApiExamples::ExampleHelper.safe_delete_file(response['uuid']) if response && response['uuid']
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
ApiExamples::RunUploadExample.call
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Uploadcare.config.secret_key = 'YOUR_SECRET_KEY'
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
puts Uploadcare::Uploader.get_upload_from_url_status(token)
|
|
4
|
+
require_relative '../support/run_upload_example'
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Uploadcare.config.secret_key = 'YOUR_SECRET_KEY'
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
info = Uploadcare::Group.info(uuid)
|
|
7
|
-
puts info.inspect
|
|
4
|
+
require_relative '../support/run_upload_example'
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Uploadcare.config.secret_key = 'YOUR_SECRET_KEY'
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
info = Uploadcare::File.info(uuid)
|
|
7
|
-
puts info.inspect
|
|
4
|
+
require_relative '../support/run_upload_example'
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Uploadcare.config.secret_key = 'YOUR_SECRET_KEY'
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
Uploadcare::Uploader.upload(source_file, store: 'auto')
|
|
4
|
+
require_relative '../support/run_upload_example'
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Uploadcare.config.secret_key = 'YOUR_SECRET_KEY'
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
Uploadcare::Uploader.upload(source_url, store: 'auto')
|
|
4
|
+
require_relative '../support/run_upload_example'
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
Uploadcare.config.secret_key = 'YOUR_SECRET_KEY'
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
'd6d34fa9-addd-472c-868d-2e5c105f9fcd',
|
|
7
|
-
'b1026315-8116-4632-8364-607e64fca723/-/resize/x800/'
|
|
8
|
-
]
|
|
9
|
-
Uploadcare::Group.create(uuids)
|
|
4
|
+
require_relative '../support/run_upload_example'
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
Uploadcare.config.public_key = 'YOUR_PUBLIC_KEY'
|
|
5
|
-
Uploadcare.config.secret_key = 'YOUR_SECRET_KEY'
|
|
6
|
-
|
|
7
|
-
source_file = File.open('image.png')
|
|
8
|
-
Uploadcare::Uploader.upload(source_file, store: 'auto')
|
|
4
|
+
require_relative '../support/run_upload_example'
|
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
Uploadcare.config.public_key = 'YOUR_PUBLIC_KEY'
|
|
5
|
-
Uploadcare.config.secret_key = 'YOUR_SECRET_KEY'
|
|
6
|
-
|
|
7
|
-
source_file = File.open('image.png')
|
|
8
|
-
Uploadcare::Uploader.upload(source_file, store: 'auto')
|
|
4
|
+
require_relative '../support/run_upload_example'
|
data/bin/console
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'bundler/setup'
|
|
5
|
-
require 'uploadcare
|
|
5
|
+
require 'uploadcare'
|
|
6
6
|
|
|
7
7
|
# You can add fixtures and/or initialization code here to make experimenting
|
|
8
8
|
# with your gem easier. You can also use a different console, if you like.
|
data/context7.json
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://context7.com/schema/context7.json",
|
|
3
|
+
"projectTitle": "Uploadcare Ruby",
|
|
4
|
+
"description": "Ruby API client for Uploadcare uploads, file management, conversions, webhooks, add-ons, and signed CDN URLs.",
|
|
5
|
+
"url": "https://context7.com/uploadcare/uploadcare-ruby",
|
|
6
|
+
"public_key": "pk_WoigIc3LrHKMjLxnI0IA2",
|
|
7
|
+
"branch": "main",
|
|
8
|
+
"folders": [
|
|
9
|
+
"lib",
|
|
10
|
+
"api_examples",
|
|
11
|
+
"examples",
|
|
12
|
+
"docs"
|
|
13
|
+
],
|
|
14
|
+
"excludeFolders": [
|
|
15
|
+
".github",
|
|
16
|
+
"bin",
|
|
17
|
+
"spec",
|
|
18
|
+
"vendor",
|
|
19
|
+
"tmp",
|
|
20
|
+
"coverage",
|
|
21
|
+
"pkg",
|
|
22
|
+
"doc",
|
|
23
|
+
"*archive*",
|
|
24
|
+
"*archived*",
|
|
25
|
+
"old",
|
|
26
|
+
"docs/old",
|
|
27
|
+
"*deprecated*",
|
|
28
|
+
"*legacy*",
|
|
29
|
+
"*previous*",
|
|
30
|
+
"*outdated*",
|
|
31
|
+
"*superseded*"
|
|
32
|
+
],
|
|
33
|
+
"excludeFiles": [
|
|
34
|
+
"CHANGELOG.md",
|
|
35
|
+
"changelog.md",
|
|
36
|
+
"CHANGELOG.mdx",
|
|
37
|
+
"changelog.mdx",
|
|
38
|
+
"LICENSE",
|
|
39
|
+
"LICENSE.md",
|
|
40
|
+
"license.md",
|
|
41
|
+
"CODE_OF_CONDUCT.md",
|
|
42
|
+
"code_of_conduct.md",
|
|
43
|
+
"Gemfile",
|
|
44
|
+
"Rakefile",
|
|
45
|
+
"uploadcare-ruby.gemspec",
|
|
46
|
+
".rspec",
|
|
47
|
+
".rubocop.yml",
|
|
48
|
+
".yardopts"
|
|
49
|
+
],
|
|
50
|
+
"rules": [
|
|
51
|
+
"Install the gem as `uploadcare-ruby` and require it with `require \"uploadcare\"`.",
|
|
52
|
+
"Prefer explicit `Uploadcare::Client` instances for application code, especially when an app uses more than one Uploadcare project.",
|
|
53
|
+
"Configure credentials with `Uploadcare::Client.new(public_key: ..., secret_key: ...)`, `Uploadcare.configure`, or the UPLOADCARE_PUBLIC_KEY and UPLOADCARE_SECRET_KEY environment variables.",
|
|
54
|
+
"Never hardcode real Uploadcare API keys in examples or application code; use environment variables or an application secrets store.",
|
|
55
|
+
"Use `client.files`, `client.groups`, `client.uploads`, `client.project`, `client.webhooks`, `client.file_metadata`, `client.addons`, and `client.conversions` for normal application workflows.",
|
|
56
|
+
"Use `client.api.rest` and `client.api.upload` when exact REST API or Upload API endpoint parity is needed.",
|
|
57
|
+
"Use `client.uploads.upload` for automatic upload method selection and `client.uploads.multipart_upload` for explicit multipart uploads.",
|
|
58
|
+
"Use `MIGRATING_V5.md` when upgrading applications from uploadcare-ruby v4.x to v5."
|
|
59
|
+
],
|
|
60
|
+
"previousVersions": [
|
|
61
|
+
{
|
|
62
|
+
"tag": "v4.4.3"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"tag": "v3.3.2"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"tag": "v2.1.2"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"tag": "v1.2.2"
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
}
|