shrine-aws-lambda 0.1.2 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d57be08878d86a78c04deae0d470e17d442c5c8f0c94b6abf3436c27697314f3
4
- data.tar.gz: 87437b1050b4d5b095811d409af005ba5f9ce80921fa4ff09c2349f5f2ac6303
3
+ metadata.gz: 5e0d7af435748ceeeb5601be1a154c47520d1dedba3614839039b0d63ec65b6b
4
+ data.tar.gz: 54f36d90cb8d3665ebc4497c8f329ea73bdfbc1bb12842dcdeb45fd4cb28cdd3
5
5
  SHA512:
6
- metadata.gz: 38b075d8edbec8c1309ed0eea89961a3bc3ac3628c0073ed2f1339acc9db7a56160b61435c7624b7c02cd67bd8f113629fb08281fd2c74c09c270c09ee76371d
7
- data.tar.gz: 22d612ad85d247ca52f0f1e2ad65132052190e8b9d94927045ac66135e1d1d13cc900009f2273db9f31abf75c8b94dc3e426eb34808ca34e137bcffc79f2d1b1
6
+ metadata.gz: 6b213faed7582e759bcc90288051067d35085734e85750b467f5ea094a7ca7833a5c350eefbdee58aa409a37bd7bcadb5b793fbb4139c9e418097a62fa28d3ce
7
+ data.tar.gz: a8ad146c2cad8786bafa27e9ef34bfe01af4972eead401514c8689f6daaf4c708353d424cd77fc8f16856bce23810e2ed1867174f9af5265974875bfda21a43e
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.2.0](https://github.com/texpert/shrine-aws-lambda/tree/0.2.0) (2022-08-28)
4
+
5
+ [Full Changelog](https://github.com/texpert/shrine-aws-lambda/compare/v0.1.2...0.2.0)
6
+
7
+ **Merged pull requests:**
8
+
9
+ - Upgrade to work with Shrine version 3 [\#3](https://github.com/texpert/shrine-aws-lambda/pull/3) ([texpert](https://github.com/texpert))
10
+
3
11
  ## [v0.1.2](https://github.com/texpert/shrine-aws-lambda/tree/v0.1.2) (2022-07-03)
4
12
 
5
13
  [Full Changelog](https://github.com/texpert/shrine-aws-lambda/compare/88f53efc0436de444f438d36b8a831b4013f5778...v0.1.2)
data/README.md CHANGED
@@ -1,8 +1,7 @@
1
1
  # Shrine::Plugins::AwsLambda
2
- Provides [AWS Lambda] integration for [Shrine] File Attachment toolkit for Ruby applications
2
+ Provides [AWS Lambda] integration for the [Shrine] File Attachment toolkit for Ruby applications
3
3
 
4
- This is a gem, renamed from initial [shrine-lambda](https://github.com/texpert/shrine-lambda) to [shrine-aws-lambda](https://github.com/texpert/shrine-aws-lambda)
5
- for clarity
4
+ This is a gem, renamed from the initial [shrine-lambda](https://github.com/texpert/shrine-lambda) to [shrine-aws-lambda](https://github.com/texpert/shrine-aws-lambda) for clarity
6
5
 
7
6
  ## Description
8
7
 
@@ -53,7 +52,7 @@ either in the [Shrine] initializer, or in [default profile][AWS profiles] in the
53
52
  region: 'your AWS bucket region' }
54
53
  ```
55
54
 
56
- Also, for Lamda functions to work, various [AWS Lamda permissions] should be managed on the [Amazon Web Services] side.
55
+ Also, for Lambda functions to work, various [AWS Lambda permissions] should be managed on the [Amazon Web Services] side.
57
56
 
58
57
  Add to the [Shrine]'s initializer file the Shrine-AWS-Lambda plugin registration with the `:callback_url` parameter,
59
58
  and the [AWS Lambda] functions list retrieval call (which will retrieve the functions list on application initialization
@@ -71,11 +70,11 @@ and will store the list into the `Shrine.opts[:lambda_function_list]` for furthe
71
70
  By default, Shrine-AWS-Lambda is using the S3 bucket named `:cache` for retrieving the original file, and the `:store`
72
71
  named S3 bucket for storing the resulting files.
73
72
 
74
- Srine-Lamda uses the [Shrine backgrounding plugin] for asynchronous operation, so this plugin should be also included
75
- into the Shrine's initializer.
73
+ Shrine-AWS-Lambda uses the [Shrine backgrounding plugin] for asynchronous operation, so this plugin should be also
74
+ included into the Shrine's initializer.
76
75
 
77
- Here is a full example of a Shrine initializer of a [Rails] application using [Roda] endpoints for presigned_url's
78
- (used for direct file uploads to [AWS S3]) and [AWS Lambda] callbacks:
76
+ Here is a full example of a Shrine initializer of a [Rails] application using a [Roda] endpoint for presigned_url
77
+ (used for direct file uploads to [AWS S3]) and [AWS Lambda] callbacks):
79
78
 
80
79
  ```ruby
81
80
  # config/initializers/shrine.rb:
@@ -94,72 +93,78 @@ if Rails.env.test?
94
93
  else
95
94
  require 'shrine/storage/s3'
96
95
 
97
- secrets = Rails.application.secrets
96
+ aws_credentials = Rails.application.credentials.aws
98
97
 
99
- s3_options = { access_key_id: secrets.aws_access_key_id,
100
- secret_access_key: secrets.aws_secret_access_key,
98
+ s3_options = { access_key_id: aws_credentials[:access_key_id],
99
+ secret_access_key: aws_credentials[:secret_access_key],
101
100
  region: 'us-east-2' }
102
101
 
103
102
  if Rails.env.production?
104
- cache_bucket = store_bucket = secrets.aws_s3_bucket
103
+ cache_bucket = store_bucket = aws_credentials.aws_s3_bucket
105
104
  else
106
105
  cache_bucket = 'texpert-test-cache'
107
106
  store_bucket = 'texpert-test-store'
108
107
  end
109
108
 
110
- Shrine.storages = {
111
- cache: Shrine::Storage::S3.new(prefix: 'cache', **s3_options.merge(bucket: cache_bucket)),
112
- store: Shrine::Storage::S3.new(prefix: 'store', **s3_options.merge(bucket: store_bucket))
113
- }
114
-
115
- lambda_callback_url = if Rails.env.development?
116
- "http://#{ENV['USER']}.localtunnel.me/rapi/lambda"
117
- else
118
- "https://#{ENV.fetch('APP_HOST')}/rapi/lambda"
119
- end
109
+ Shrine.storages = { cache: Shrine::Storage::S3.new(prefix: 'cache', **s3_options.merge!(bucket: cache_bucket)),
110
+ store: Shrine::Storage::S3.new(prefix: 'store', **s3_options.merge!(bucket: store_bucket)) }
120
111
 
121
- shrine.plugin :aws_lambda, s3_options.merge(callback_url: lambda_callback_url)
122
- Shrine.lambda_function_list
123
-
124
- Shrine.plugin :presign_endpoint, presign_options: ->(request) do
125
- filename = request.params['filename']
126
- extension = File.extname(filename)
127
- content_type = Rack::Mime.mime_type(extension)
112
+ ActiveSupport::Reloader.to_prepare do
113
+ lambda_callback_url = if Rails.env.development? && NGROK_ENABLED
114
+ "#{NGROK_URL}/rapi/lambda"
115
+ else
116
+ "https://#{ENV['APP_HOST'] || 'localhost'}/rapi/lambda"
117
+ end
128
118
 
129
- {
130
- content_length_range: 0..1.gigabyte, # limit filesize to 1 GB
131
- content_disposition: "attachment; filename=\"#{filename}\"", # download with original filename
132
- content_type: content_type, # set correct content type
133
- }
119
+ Shrine.plugin :aws_lambda, s3_options.merge!(callback_url: lambda_callback_url)
120
+ Shrine.lambda_function_list
134
121
  end
135
122
  end
136
123
 
137
124
  Shrine.plugin :activerecord
138
125
  Shrine.plugin :backgrounding
139
126
  Shrine.plugin :cached_attachment_data # for forms
140
- Shrine.plugin :logging, logger: Rails.logger
127
+
128
+ Shrine.logger = Rails.logger
129
+ Shrine.plugin :instrumentation
130
+
131
+ Shrine.plugin :presign_endpoint, presign_options: lambda { |request|
132
+ filename = request.params['filename']
133
+ extension = File.extname(filename)
134
+ content_type = Rack::Mime.mime_type(extension)
135
+
136
+ { content_length_range: 0..1.gigabyte, # limit filesize to 1 GB
137
+ content_disposition: "attachment; filename=\"#{filename}\"", # download with original filename
138
+ content_type: content_type } # set correct content type
139
+ }
140
+
141
141
  Shrine.plugin :rack_file # for non-Rails apps
142
142
  Shrine.plugin :remote_url, max_size: 1.gigabyte
143
143
 
144
- Shrine::Attacher.promote { |data| PromoteJob.perform_later(data) }
145
- Shrine::Attacher.delete { |data| DeleteJob.perform_later(data) }
144
+ Shrine::Attacher.promote_block { PromoteJob.enqueue(self.class.name, record.class.name, record.id, name, file_data) }
145
+ Shrine::Attacher.destroy_block { DeleteJob.enqueue(self.class.name, data) }
146
+ ```
147
+
148
+ Take notice that the promote job is a default, not AWS Lambda job:
146
149
 
150
+ ```
151
+ Shrine::Attacher.promote_block { PromoteJob.enqueue(self.class.name, record.class.name, record.id, name, file_data) }
147
152
  ```
148
153
 
149
- Take notice that the promote job is a default `Shrine::Attacher.promote { |data| PromoteJob.perform_later(data) }`.
150
154
  This is made to be able to use other than AWS storages in the test environment (like Shrine's `FileSystem` storage)
151
- and, also, other uploaders which are not using [AWS Lambda]. This job better to be overrided to a `LambdaPromoteJob`
152
- directly in the uploaders' classes which will use [AWS Lambda].
155
+ and, also, other uploaders which are not using [AWS Lambda]. To use an AWS Lambda job, this job must be overridden
156
+ to a `LambdaPromoteJob` directly in the uploaders' classes which will use [AWS Lambda] - see below in the **Usage**
157
+ chapter.
153
158
 
154
- Another thing used in this initializer is the [localtunnel] application for exposing the localhost to the world for
159
+ Another thing used in this initializer is the [ngrok-wrapper] gem for exposing the localhost to the world for
155
160
  catching the Lambda callback requests.
156
161
 
157
162
  #### How it works
158
163
 
159
- Shrine-Lamnda works in such a way that an "assembly" should be created in the `LambdaUploader`, which contains all
164
+ Shrine-AWS-Lambda works in such a way that an "assembly" should be created in the `LambdaUploader`, which contains all
160
165
  the information about how the file should be processed. A random generated string is appended to the assembly, stored
161
166
  into the cached file metadata, and used by the Lambda function to sign the requests to the `:lambda_callback_url`,
162
- along with the `:access_key_id` from the temporary credentials Lambda function is running with.
167
+ along with the AWS `:access_key_id` from the AWS credentials Lambda function is running with.
163
168
 
164
169
  Processing itself happens asynchronously - the invoked Lambda function will issue a PUT HTTP request to the
165
170
  `:lambda_callback_url`, specified in the Shrine's initializer, with the request's payload containing the processing
@@ -168,9 +173,9 @@ results.
168
173
  The request should be intercepted by a endpoint at the `:lambda_callback_url`, and its payload transferred to the
169
174
  `lambda_save` method on successful request authorization.
170
175
 
171
- The authorization is calculatating the HTTP request signature using the random string stored in the cached file and
172
- the Lambda function's `:access_key_id` received in the request authorization header. Then, the calculated signature is
173
- compared to the received in the same authorization header Lambda signature.
176
+ The authorization is calculating the HTTP request signature using the random string stored in the cached file and
177
+ the AWS Lambda function's `:access_key_id` received in the request authorization header. Then, the calculated
178
+ signature is compared to the received in the same authorization header AWS Lambda signature.
174
179
 
175
180
  #### Usage
176
181
 
@@ -182,7 +187,11 @@ Shrine-AWS-Lambda assemblies are built inside the `#lambda_process_versions` met
182
187
  # frozen_string_literal: true
183
188
 
184
189
  class LambdaUploader < Uploader
185
- Attacher.promote { |data| LambdaPromoteJob.perform_later(data) } unless Rails.env.test?
190
+ unless Rails.env.test?
191
+ Attacher.promote_block do
192
+ LambdaPromoteJob.enqueue(self.class.name, record.class.name, record.id, name, file_data)
193
+ end
194
+ end
186
195
 
187
196
  plugin :upload_options, store: ->(_io, context) do
188
197
  if %i[avatar logo].include?(context[:name])
@@ -219,7 +228,6 @@ class LambdaUploader < Uploader
219
228
  assembly
220
229
  end
221
230
  end
222
-
223
231
  ```
224
232
 
225
233
  The above example is built to interact with the [lambda-image-resize] function, which is using the [Sharp] Javascript
@@ -240,14 +248,13 @@ The default options used by Shrine-AWS-Lambda plugin are the following:
240
248
  target_storage: :store }
241
249
  ```
242
250
 
243
- These options could be overrided in the `LambdaUploader` specifying them as the `assembly` keys:
251
+ These options could be overridden in the `LambdaUploader` specifying them as the `assembly` keys:
244
252
 
245
253
  ```ruby
246
- assembly[:callbackURL] = some_callback_url]
247
- assembly[:copy_original = false # If this is `false`, only the processed file versions will be stored
254
+ assembly[:callbackURL] = some_callback_url
255
+ assembly[:copy_original] = false # If this is `false`, only the processed file versions will be stored
248
256
  assembly[:storages] = Shrine.buckets_to_use(%i[cache store other_store])
249
257
  assembly[:target_storage] = :other_store
250
-
251
258
  ```
252
259
 
253
260
  Any S3 buckets could be specified, as long as the buckets are defined in the Shrine's initializer file.
@@ -294,7 +301,6 @@ module RAPI
294
301
  end
295
302
  end
296
303
  end
297
-
298
304
  ```
299
305
 
300
306
  #### Backgrounding
@@ -302,7 +308,13 @@ end
302
308
  Even though submitting a Lambda assembly doesn't require any uploading, it still does a HTTP request, so it is better
303
309
  to put it into a background job. This is configured in the `LambdaUploader` class:
304
310
 
305
- `Attacher.promote { |data| LambdaPromoteJob.perform_later(data) } unless Rails.env.test?`
311
+ ```ruby
312
+ unless Rails.env.test?
313
+ Attacher.promote_block do
314
+ LambdaPromoteJob.enqueue(self.class.name, record.class.name, record.id, name, file_data)
315
+ end
316
+ end
317
+ ```
306
318
 
307
319
  Then the job file should be implemented:
308
320
 
@@ -311,9 +323,11 @@ Then the job file should be implemented:
311
323
 
312
324
  # frozen_string_literal: true
313
325
 
314
- class LambdaPromoteJob < ApplicationJob
315
- def perform(data)
316
- Timeout.timeout(30) { Shrine::Attacher.lambda_process(data) }
326
+ class LambdaPromoteJob < Que::Job
327
+ def run(...)
328
+ ActiveRecord::Base.transaction do
329
+ Shrine::Attacher.lambda_process(...)
330
+ end
317
331
  end
318
332
  end
319
333
  ```
@@ -360,7 +374,7 @@ by the following command:
360
374
  $ gem build shrine-aws-lambda.gemspec
361
375
  ```
362
376
 
363
- Assuming the version was set to `0.1.2`, a `shrine-aws-lambda-0.1.2.gem` binary file will be generated at the root of
377
+ Assuming the version was set to `0.2.0`, a `shrine-aws-lambda-0.2.0.gem` binary file will be generated at the root of
364
378
  the app (repo).
365
379
 
366
380
  - The binary file shouldn't be added into the `git` tree, it will be pushed into the RubyGems and to the GitHub releases
@@ -368,7 +382,7 @@ the app (repo).
368
382
  #### Pushing a new gem release to RubyGems
369
383
 
370
384
  ```bash
371
- $ gem push shrine-aws-lambda-0.1.2.gem # don't forget to specify the correct version number
385
+ $ gem push shrine-aws-lambda-0.2.0.gem # don't forget to specify the correct version number
372
386
  ```
373
387
 
374
388
  #### Crafting the new release on GitHub
@@ -403,12 +417,12 @@ article], which pointed me to use the [Sharp] library for image resizing.
403
417
  [Amazon Web Services]: https://aws.amazon.com
404
418
  [AWS blog article]: https://aws.amazon.com/blogs/compute/resize-images-on-the-fly-with-amazon-s3-aws-lambda-and-amazon-api-gateway/
405
419
  [AWS Lambda]: https://aws.amazon.com/lambda
406
- [AWS Lamda permissions]: https://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html
420
+ [AWS Lambda permissions]: https://docs.aws.amazon.com/lambda/latest/dg/intro-permission-model.html
407
421
  [AWS profiles]: https://docs.aws.amazon.com/cli/latest/userguide/cli-multiple-profiles.html
408
422
  [AWS S3]: https://aws.amazon.com/s3/
409
423
  [Janko]: https://github.com/janko-m
410
424
  [lambda-image-resize]: https://github.com/texpert/lambda-image-resize.js
411
- [localtunnel]: https://github.com/localtunnel/localtunnel
425
+ [ngrok-wrapper]: https://github.com/texpert/ngrok-wrapper
412
426
  [Rails]: http://rubyonrails.org
413
427
  [Roda]: http://roda.jeremyevans.net
414
428
  [Sharp]: https://github.com/lovell/sharp
@@ -3,7 +3,7 @@
3
3
  class Shrine
4
4
  module Plugins
5
5
  module AwsLambda
6
- VERSION = '0.1.2'
6
+ VERSION = '0.2.0'
7
7
  end
8
8
  end
9
9
  end
@@ -59,9 +59,12 @@ class Shrine
59
59
  module AttacherClassMethods
60
60
  # Loads the attacher from the data, and triggers its instance AWS Lambda
61
61
  # processing method. Intended to be used in a background job.
62
- def lambda_process(data)
63
- attacher = load(data)
64
- attacher.lambda_process(data)
62
+ def lambda_process(attacher_class, record_class, record_id, name, file_data)
63
+ attacher_class = Object.const_get(attacher_class)
64
+ record = Object.const_get(record_class).find(record_id) # if using Active Record
65
+
66
+ attacher = attacher_class.retrieve(model: record, name: name, file: file_data)
67
+ attacher.lambda_process
65
68
  attacher
66
69
  end
67
70
 
@@ -85,12 +88,28 @@ class Shrine
85
88
  # @return [false] if signature in received headers does't match locally computed AWS signature
86
89
  def lambda_authorize(headers, body)
87
90
  result = JSON.parse(body)
88
- attacher = load(result.delete('context'))
91
+ context = result['context']
92
+
93
+ context_record = context['record']
94
+ record_class = context_record[0]
95
+ record_id = context_record[1]
96
+ record = Object.const_get(record_class).find(record_id)
97
+ attacher_name = context['name']
98
+ attacher = record.__send__(:"#{attacher_name}_attacher")
99
+
100
+ return false unless signature_matched?(attacher, headers, body)
101
+
102
+ [attacher, result]
103
+ end
104
+
105
+ private
106
+
107
+ def signature_matched?(attacher, headers, body)
89
108
  incoming_auth_header = auth_header_hash(headers['Authorization'])
90
109
 
91
110
  signer = build_signer(
92
111
  incoming_auth_header['Credential'].split('/'),
93
- JSON.parse(attacher.record.__send__(:"#{attacher.data_attribute}") || '{}').dig('metadata', 'key') || 'key',
112
+ JSON.parse(attacher.record.__send__(:"#{attacher.attribute}") || '{}').dig('metadata', 'key') || 'key',
94
113
  headers['x-amz-security-token']
95
114
  )
96
115
  signature = signer.sign_request(http_method: 'PUT',
@@ -98,13 +117,10 @@ class Shrine
98
117
  headers: { 'X-Amz-Date' => headers['X-Amz-Date'] },
99
118
  body: body)
100
119
  calculated_signature = auth_header_hash(signature.headers['authorization'])['Signature']
101
- return false if incoming_auth_header['Signature'] != calculated_signature
102
120
 
103
- [attacher, result]
121
+ incoming_auth_header['Signature'] == calculated_signature
104
122
  end
105
123
 
106
- private
107
-
108
124
  def build_signer(headers, secret_access_key, security_token = nil)
109
125
  Aws::Sigv4::Signer.new(
110
126
  service: headers[3],
@@ -141,8 +157,8 @@ class Shrine
141
157
  # errors. No more response analysis is performed, because Lambda is invoked asynchronously (note the
142
158
  # `invocation_type`: 'Event' in the `invoke` call). The results will be sent by Lambda by HTTP requests to
143
159
  # the specified `callbackUrl`.
144
- def lambda_process(data)
145
- cached_file = uploaded_file(data['attachment'])
160
+ def lambda_process
161
+ cached_file = uploaded_file(file)
146
162
  assembly = lambda_default_values
147
163
  assembly.merge!(store.lambda_process_versions(cached_file, context))
148
164
  function = assembly.delete(:function)
@@ -150,13 +166,16 @@ class Shrine
150
166
  raise Error, "Function #{function} not available on Lambda!" unless function_available?(function)
151
167
 
152
168
  prepare_assembly(assembly, cached_file, context)
153
- assembly[:context] = data.except('attachment', 'action', 'phase')
169
+ assembly[:context] = { 'record' => [record.class.name, record.id],
170
+ 'name' => name,
171
+ 'shrine_class' => self.class.name }
154
172
  response = lambda_client.invoke(function_name: function,
155
173
  invocation_type: 'Event',
156
174
  payload: assembly.to_json)
157
175
  raise Error, "#{response.function_error}: #{response.payload.read}" if response.function_error
158
176
 
159
- swap(cached_file) || _set(cached_file)
177
+ set(cached_file)
178
+ atomic_persist(cached_file)
160
179
  end
161
180
 
162
181
  # Receives the `result` hash after Lambda request was authorized. The result could contain an array of
@@ -164,7 +183,7 @@ class Shrine
164
183
  # attached file was just moved to the target storage bucket.
165
184
  #
166
185
  # Deletes the signing key, if it is present in the original file's metadata, converts the result to a JSON
167
- # string, and writes this string into the `data_attribute` of the Shrine attacher's record.
186
+ # string, and writes this string into the `attribute` of the Shrine attacher's record.
168
187
  #
169
188
  # Chooses the `save_method` either for the ActiveRecord or for Sequel, and saves the record.
170
189
  # @param [Hash] result
@@ -179,7 +198,7 @@ class Shrine
179
198
  result.to_json
180
199
  end
181
200
 
182
- record.__send__(:"#{data_attribute}=", attr_content)
201
+ record.__send__(:"#{attribute}=", attr_content)
183
202
  save_method = case record
184
203
  when ActiveRecord::Base
185
204
  :save
@@ -28,7 +28,7 @@ Gem::Specification.new do |gem|
28
28
 
29
29
  gem.add_dependency 'aws-sdk-lambda', '~> 1.0'
30
30
  gem.add_dependency 'aws-sdk-s3', '~> 1.2'
31
- gem.add_dependency 'shrine', '~> 2.6'
31
+ gem.add_dependency 'shrine', '~> 3.4'
32
32
 
33
33
  gem.add_development_dependency 'activerecord', '>= 4.2.0'
34
34
  gem.add_development_dependency 'dotenv'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shrine-aws-lambda
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aurel Branzeanu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-07-03 00:00:00.000000000 Z
11
+ date: 2022-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-lambda
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '2.6'
47
+ version: '3.4'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '2.6'
54
+ version: '3.4'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: activerecord
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -216,7 +216,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
216
216
  - !ruby/object:Gem::Version
217
217
  version: '0'
218
218
  requirements: []
219
- rubygems_version: 3.1.6
219
+ rubygems_version: 3.3.10
220
220
  signing_key:
221
221
  specification_version: 4
222
222
  summary: AWS Lambda integration plugin for Shrine.