salesforce_streamer 2.0.0.rc1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 980626b26a53a56e8fb6fd2028e538ffd667cbe938a1aa1011c4184813d2936d
4
- data.tar.gz: b6ece556e2e34186b9ad77f445c26ebf6532170e4a9f7a8d0662e309775c9427
3
+ metadata.gz: 1b4745cb1c8f38229ac4be01e746a7b865458c37e0d293f3505bfe9803cce20c
4
+ data.tar.gz: 290378a24b830fedd86290a06deaf5050fd1187c22467cadc6b1278aee19cebf
5
5
  SHA512:
6
- metadata.gz: 1920656978db1b707ba61bd90c7026988b99c9dfbb2c7489f4a8554df97f1ad9000885fa619bff884257fd5794225ba3c3ab23b3172b6753ea57ec8f76e6bb05
7
- data.tar.gz: '0099d97a9cb7774c0fe274b0ee46bb68da87dca38f6113310539248f309111341a4a3e917476e4ca686413cf8cd22e5551f6c917a774a60ffab6541f9ad04889'
6
+ metadata.gz: 228d3f363b0b0bb292e94c4776c74fd8930f616250664fb586cfafa2695fcdde07f754f850c430e87ec12b9473046d733975d4c5ac3f9d9e70fd6be0ef8baa73
7
+ data.tar.gz: '0850171e7c9762b7cf498a8c9066b21482cab7e69f30d7a72d9cc0ca7b12c90ab5ea167ae312614d6d25060558cfd7aa2a880f60e6d7eaacf8229e916e14c61b'
@@ -1,7 +1,7 @@
1
- # automatically approve PRs submitted by Dependabot
1
+ # automatically approve PRs submitted by Dependabot or Renofidev
2
2
  # this will allow Dependabot to automatically merge dependency update PRs where CI passes
3
3
  # from: https://github.com/hmarr/auto-approve-action
4
- name: Auto approve Dependabot PRs
4
+ name: Auto approve dependency upgrades PRs
5
5
 
6
6
  on:
7
7
  pull_request
@@ -11,6 +11,6 @@ jobs:
11
11
  runs-on: ubuntu-latest
12
12
  steps:
13
13
  - uses: hmarr/auto-approve-action@v2.0.0
14
- if: github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]'
14
+ if: github.actor == 'dependabot[bot]' || github.actor == 'dependabot-preview[bot]' || github.actor == 'renofidev'
15
15
  with:
16
16
  github-token: "${{ secrets.GITHUB_TOKEN }}"
@@ -0,0 +1,19 @@
1
+ name: automerge
2
+ on:
3
+ pull_request_review:
4
+ types:
5
+ - submitted
6
+ check_suite:
7
+ types:
8
+ - completed
9
+ status: {}
10
+ jobs:
11
+ automerge:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - name: automerge
15
+ uses: "pascalgn/automerge-action@v0.11.0"
16
+ env:
17
+ GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
18
+ MERGE_METHOD: squash
19
+ MERGE_DELETE_BRANCH: true
@@ -3,6 +3,38 @@
3
3
  Sorted so that the most recent change logs are near the top. Only significant
4
4
  changes are logged in the change log.
5
5
 
6
+ ## 2020-08-17 Scott Serok [scott@renofi.com](mailto:scott@renofi.com)
7
+
8
+ v2.1 changes the expected interface of `Configuration#replay_adapter`.
9
+
10
+ Normally this breaking change would require a major version bump, but since the
11
+ functionality today is quiet broken we can call this a major bug fix.
12
+
13
+ The `config.replay_adapter` should be an object that has an interface like Hash.
14
+ It must respond to `[]` and `[]=`. By default the adapter is an empty hash. If
15
+ you want your push topic replayId to persist between restarts, then you should
16
+ implement a class with an appropriate interface.
17
+
18
+ ```ruby
19
+ class MyReplayAdapter
20
+ def [](channel)
21
+ MyPersistence.get(channel)
22
+ end
23
+
24
+ def []=(channel, replay_id)
25
+ MyPersistence.set(channel, replay_id)
26
+ end
27
+ end
28
+ ```
29
+
30
+ This change was sparked by a misunderstanding of the
31
+ `Restforce::Concerns::Streaming::ReplayExtension` replay handlers.
32
+ SalesforceStreamer can eliminate some complexity and fix a bug by delegating the
33
+ responsibility of maintaining the current replayId to that ReplayExtension. The
34
+ object will be used on each request/response cycle to record and read the latest
35
+ replayId as long as the object assigned to `config.replay_adapter` responds to
36
+ `[]` and `[]=`.
37
+
6
38
  ## 2020-08-04 Scott Serok [scott@renofi.com](mailto:scott@renofi.com)
7
39
 
8
40
  v2.0 is released as a major simplification of this library. There are 2
@@ -61,7 +93,7 @@ To retrieve the replayId before subscribing to a PushTopic,
61
93
  configure an adapter that returns an integer.
62
94
 
63
95
  SalesforceStreamer.config.replay_adapter = proc { |topic|
64
- MyStore.fetch_replay_id(topic.name) || -1
96
+ (MyStore.fetch_replay_id(topic.name) || -1).to_i
65
97
  }
66
98
 
67
99
  This will be used to set the replayId value when subscribing to the PushTopic.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- salesforce_streamer (2.0.0.rc1)
4
+ salesforce_streamer (2.2.0)
5
5
  dry-initializer (~> 3.0)
6
6
  faye (~> 1.4)
7
7
  restforce (>= 4.2, < 6.0)
@@ -13,16 +13,14 @@ GEM
13
13
  public_suffix (>= 2.0.2, < 5.0)
14
14
  ast (2.4.1)
15
15
  byebug (11.1.3)
16
- codecov (0.2.3)
17
- colorize
16
+ codecov (0.2.12)
18
17
  json
19
18
  simplecov
20
- colorize (0.8.1)
21
19
  cookiejar (0.3.3)
22
20
  diff-lcs (1.4.4)
23
21
  docile (1.3.2)
24
- dry-initializer (3.0.3)
25
- em-http-request (1.1.6)
22
+ dry-initializer (3.0.4)
23
+ em-http-request (1.1.7)
26
24
  addressable (>= 2.3.4)
27
25
  cookiejar (!= 0.3.1)
28
26
  em-socksify (>= 0.3)
@@ -31,8 +29,9 @@ GEM
31
29
  em-socksify (0.3.2)
32
30
  eventmachine (>= 1.0.0.beta.4)
33
31
  eventmachine (1.2.7)
34
- faraday (1.0.1)
32
+ faraday (1.1.0)
35
33
  multipart-post (>= 1.2, < 3)
34
+ ruby2_keywords
36
35
  faraday_middleware (1.0.0)
37
36
  faraday (~> 1.0)
38
37
  faye (1.4.0)
@@ -49,56 +48,59 @@ GEM
49
48
  hashie (4.1.0)
50
49
  http_parser.rb (0.6.0)
51
50
  json (2.3.1)
52
- jwt (2.2.1)
51
+ jwt (2.2.2)
53
52
  multi_json (1.15.0)
54
53
  multipart-post (2.1.1)
55
- parallel (1.19.2)
56
- parser (2.7.1.4)
54
+ parallel (1.20.0)
55
+ parser (2.7.2.0)
57
56
  ast (~> 2.4.1)
58
- public_suffix (4.0.5)
57
+ public_suffix (4.0.6)
59
58
  rack (2.2.3)
60
59
  rainbow (3.0.0)
61
60
  rake (13.0.1)
62
- regexp_parser (1.7.1)
63
- restforce (5.0.0)
61
+ regexp_parser (1.8.2)
62
+ restforce (5.0.3)
64
63
  faraday (>= 0.9.0, <= 2.0)
65
64
  faraday_middleware (>= 0.8.8, <= 2.0)
66
65
  hashie (>= 1.2.0, < 5.0)
67
66
  jwt (>= 1.5.6)
68
67
  rexml (3.2.4)
69
- rspec (3.9.0)
70
- rspec-core (~> 3.9.0)
71
- rspec-expectations (~> 3.9.0)
72
- rspec-mocks (~> 3.9.0)
73
- rspec-core (3.9.2)
74
- rspec-support (~> 3.9.3)
75
- rspec-expectations (3.9.2)
68
+ rspec (3.10.0)
69
+ rspec-core (~> 3.10.0)
70
+ rspec-expectations (~> 3.10.0)
71
+ rspec-mocks (~> 3.10.0)
72
+ rspec-core (3.10.0)
73
+ rspec-support (~> 3.10.0)
74
+ rspec-expectations (3.10.0)
76
75
  diff-lcs (>= 1.2.0, < 2.0)
77
- rspec-support (~> 3.9.0)
78
- rspec-mocks (3.9.1)
76
+ rspec-support (~> 3.10.0)
77
+ rspec-mocks (3.10.0)
79
78
  diff-lcs (>= 1.2.0, < 2.0)
80
- rspec-support (~> 3.9.0)
81
- rspec-support (3.9.3)
82
- rubocop (0.88.0)
79
+ rspec-support (~> 3.10.0)
80
+ rspec-support (3.10.0)
81
+ rubocop (1.2.0)
83
82
  parallel (~> 1.10)
84
- parser (>= 2.7.1.1)
83
+ parser (>= 2.7.1.5)
85
84
  rainbow (>= 2.2.2, < 4.0)
86
- regexp_parser (>= 1.7)
85
+ regexp_parser (>= 1.8)
87
86
  rexml
88
- rubocop-ast (>= 0.1.0, < 1.0)
87
+ rubocop-ast (>= 1.0.1)
89
88
  ruby-progressbar (~> 1.7)
90
89
  unicode-display_width (>= 1.4.0, < 2.0)
91
- rubocop-ast (0.3.0)
92
- parser (>= 2.7.1.4)
93
- rubocop-performance (1.7.1)
94
- rubocop (>= 0.82.0)
95
- rubocop-rspec (1.42.0)
90
+ rubocop-ast (1.1.1)
91
+ parser (>= 2.7.1.5)
92
+ rubocop-performance (1.8.1)
96
93
  rubocop (>= 0.87.0)
94
+ rubocop-ast (>= 0.4.0)
95
+ rubocop-rspec (2.0.0)
96
+ rubocop (~> 1.0)
97
+ rubocop-ast (>= 1.1.0)
97
98
  ruby-progressbar (1.10.1)
98
- simplecov (0.18.5)
99
+ ruby2_keywords (0.0.2)
100
+ simplecov (0.19.1)
99
101
  docile (~> 1.1)
100
102
  simplecov-html (~> 0.11)
101
- simplecov-html (0.12.2)
103
+ simplecov-html (0.12.3)
102
104
  unicode-display_width (1.7.0)
103
105
  websocket-driver (0.7.3)
104
106
  websocket-extensions (>= 0.1.0)
data/README.md CHANGED
@@ -20,33 +20,11 @@ And then execute:
20
20
 
21
21
  ## Usage
22
22
 
23
- ### Middleware
24
-
25
- You can initialize the streamer server with any number of middleware classes.
26
- When a message is received by a PushTopic subscription, the chain of middleware
27
- classes are executed before the message handler is called.
28
-
29
- ```ruby
30
- # config/initializers/streamer.rb
31
- class MySimpleMiddleware
32
- def initialize(handler)
33
- @handler = handler
34
- end
35
- def call(message)
36
- @handler.call(message)
37
- end
38
- end
39
-
40
- SalesforceStreamer.config.use_middleware MySimpleMiddleware
41
- ```
42
-
43
23
  ### Configure Push Topics
44
24
 
45
- Create a YAML file to configure your server subscriptions. The configuration
46
- for each subscription must have a nested `salesforce:` key. These settings will
47
- be synced to your Salesforce instance when the `-x` flag is set on the command
48
- line. For more information about the `replay:` and `notify_fields_for` options
49
- please see the Salesforce Streaming API reference documentation.
25
+ Create a YAML file to configure your PushTopic subscriptions. When streamer
26
+ starts up it will check for any differences between Salesforce PushTopics and
27
+ this yaml and update any differences when `config.manage_topics = true`.
50
28
 
51
29
  ```yaml
52
30
  # config/streamer.yml
@@ -71,14 +49,6 @@ production:
71
49
  <<: *DEFAULT
72
50
  ```
73
51
 
74
- It's important to note that the way push topics are managed is by the Salesforce
75
- name attribute. This should uniquely identify each push topic. It is not
76
- recommended to change the name of your push topic definitions; otherwise, the
77
- push topic manager will not find a push topic in Salesforce resulting in the
78
- creation of a brand new push topic. If the push topic manager identifies a
79
- difference in any of the other Salesforce attributes, then it will update the
80
- push topic in Salesforce before starting the streaming server.
81
-
82
52
  ### Define Message Handlers
83
53
 
84
54
  Define your handlers somewhere in your project. They must respond to either
@@ -88,14 +58,17 @@ Define your handlers somewhere in your project. They must respond to either
88
58
  # lib/account_change_handler.rb
89
59
  # Handle account changes inline
90
60
  class AccountChangeHandler
91
- def self.call(message)
92
- puts message
61
+ class << self
62
+ def call(message)
63
+ puts message
64
+ end
93
65
  end
94
66
  end
95
67
 
96
68
  # Handle account changes asynchronously
97
69
  class AccountChangeHandler
98
70
  include Sidekiq::Worker
71
+
99
72
  def perform(message)
100
73
  puts message
101
74
  end
@@ -113,13 +86,14 @@ Configure the `SalesforceStreamer` module.
113
86
  ```ruby
114
87
  # config/initializers/salesforce_streamer.rb
115
88
 
116
- SalesforceStreamer.config.logger = Logger.new(STDERR, level: 'INFO')
117
- SalesforceStreamer.config.exception_adapter = proc { |e| puts e }
118
- SalesforceStreamer.config.replay_adapter = proc { |topic|
119
- topic.id || Store.get(topic.name) || topic.replay
120
- }
121
- SalesforceStreamer.config.use_middleware AfterMessageReceived
122
- SalesforceStreamer.config.manage_topics = true
89
+ SalesforceStreamer.configure do |config|
90
+ config.logger = Logger.new(STDERR, level: 'INFO')
91
+ config.exception_adapter = proc { |e| puts e }
92
+ config.replay_adapter = MyReplayAdapter
93
+ config.use_middleware AfterMessageReceived
94
+ config.use_faye_extension ErrorLoggingExtension.new
95
+ config.manage_topics = true
96
+ end
123
97
  ```
124
98
 
125
99
  ### Launch The Streamer
@@ -158,6 +132,59 @@ By default, the executable will load the YAML based on the `RACK_ENV` environmen
158
132
  variable, or default to `:development` if not set. You can override this by
159
133
  setting the `config.environment = :integration`
160
134
 
135
+ ### Message Handling Middleware
136
+
137
+ You can initialize the streamer server with any number of middleware classes.
138
+ When a message is received by a PushTopic subscription, the chain of middleware
139
+ classes are executed before the message handler is called.
140
+
141
+ ```ruby
142
+ # config/initializers/streamer.rb
143
+ class MySimpleMiddleware
144
+ def initialize(handler)
145
+ @handler = handler
146
+ end
147
+
148
+ def call(message)
149
+ @handler.call(message)
150
+ end
151
+ end
152
+
153
+ SalesforceStreamer.config.use_middleware MySimpleMiddleware
154
+ ```
155
+
156
+ ### ReplayAdapter
157
+
158
+ The `config.replay_adapter` should be an object that has an interface like Hash.
159
+ It must respond to `[]` and `[]=`. By default the adapter is an empty hash. If
160
+ you want your push topic replayId to persist between restarts, then you should
161
+ implement a class with an appropriate interface.
162
+
163
+ ```ruby
164
+ class MyReplayAdapter
165
+ def [](channel)
166
+ Persistence.get(channel)
167
+ end
168
+
169
+ def []=(channel, replay_id)
170
+ Persistence.set(channel, replay_id)
171
+ end
172
+ end
173
+ ```
174
+
175
+ This adapter will be used directly by `Restforce::ReplayExtension`.
176
+
177
+ ### Use Faye Extension
178
+
179
+ The `config.use_faye_extension` should be given an object that responds to
180
+ `.incoming(message, callback)` or `.outgoing(message, callback)` or both. Find
181
+ out more about extensions from
182
+ [Faye](https://github.com/faye/faye/blob/master/spec/ruby/server/extensions_spec.rb)
183
+ specs.
184
+
185
+ Any configured extensions are added to the Faye client used by the Restforce
186
+ client when starting up the server.
187
+
161
188
  ## Development
162
189
 
163
190
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -58,4 +58,8 @@ module SalesforceStreamer
58
58
  def self.config
59
59
  Configuration.instance
60
60
  end
61
+
62
+ def self.configure
63
+ yield Configuration.instance
64
+ end
61
65
  end
@@ -32,7 +32,7 @@ module SalesforceStreamer
32
32
  end
33
33
 
34
34
  o.on '-v', '--verbose LEVEL', 'Set the log level (default no logging)' do |arg|
35
- @config.logger = Logger.new(STDERR, level: arg)
35
+ @config.logger = Logger.new($stderr, level: arg)
36
36
  end
37
37
 
38
38
  o.on '-V', '--version', 'Print the version information' do
@@ -3,25 +3,30 @@ module SalesforceStreamer
3
3
  class Configuration
4
4
  attr_accessor :environment, :logger, :require_path, :config_file,
5
5
  :manage_topics, :exception_adapter, :replay_adapter
6
- attr_reader :middleware
6
+ attr_reader :middleware, :faye_extensions
7
7
 
8
8
  class << self
9
9
  attr_writer :instance
10
- end
11
10
 
12
- def self.instance
13
- @instance ||= new
11
+ def configure
12
+ yield instance
13
+ end
14
+
15
+ def instance
16
+ @instance ||= new
17
+ end
14
18
  end
15
19
 
16
20
  def initialize
17
21
  @environment = ENV['RACK_ENV'] || :development
18
22
  @logger = Logger.new(IO::NULL)
19
23
  @exception_adapter = proc { |exc| fail(exc) }
20
- @replay_adapter = proc { |topic| topic.id || topic.replay }
24
+ @replay_adapter = Hash.new { |hash, key| hash[key] = -1 }
21
25
  @manage_topics = false
22
26
  @config_file = './config/streamer.yml'
23
27
  @require_path = './config/environment'
24
28
  @middleware = []
29
+ @faye_extensions = [ReplayIdErrorExtension.new]
25
30
  end
26
31
 
27
32
  def manage_topics?
@@ -33,6 +38,11 @@ module SalesforceStreamer
33
38
  @middleware << [klass, args, block]
34
39
  end
35
40
 
41
+ # adds a Faye extension
42
+ def use_faye_extension(extension)
43
+ @faye_extensions << extension
44
+ end
45
+
36
46
  # returns a ready to use chain of middleware
37
47
  def middleware_runner(last_handler)
38
48
  @middleware.reduce(last_handler) do |next_handler, current_handler|
@@ -34,7 +34,7 @@ module SalesforceStreamer
34
34
  @handler = Object.const_get(@handler)
35
35
  true
36
36
  rescue NameError, TypeError => e
37
- message = 'handler=' + @handler.to_s + ' exception=' + e.to_s
37
+ message = "handler=#{@handler} exception=#{e}"
38
38
  raise(PushTopicHandlerMissingError, message)
39
39
  end
40
40
 
@@ -53,7 +53,7 @@ module SalesforceStreamer
53
53
  if constant.respond_to? :call
54
54
  constant
55
55
  elsif constant.respond_to? :perform_async
56
- proc { |message| handler_constant.perform_async message }
56
+ proc { |message| constant.perform_async message }
57
57
  else
58
58
  fail(UnprocessableHandlerError, constant)
59
59
  end
@@ -8,10 +8,8 @@ module SalesforceStreamer
8
8
  @client.authenticate!
9
9
  end
10
10
 
11
- def subscribe(*args)
12
- @client.subscribe(args) do
13
- yield
14
- end
11
+ def subscribe(*args, &block)
12
+ @client.subscribe(args, &block)
15
13
  end
16
14
 
17
15
  # Returns nil or an instance of Restforce::SObject
@@ -27,19 +27,19 @@ module SalesforceStreamer
27
27
  return @client if @client
28
28
  @client = Restforce.new
29
29
  @client.authenticate!
30
- @client.faye.add_extension ReplayIdErrorExtension.new
30
+ Configuration.instance.faye_extensions.each do |extension|
31
+ Log.debug %(adding Faye extension #{extension})
32
+ @client.faye.add_extension extension
33
+ end
31
34
  @client
32
35
  end
33
36
 
34
37
  def start_em
35
38
  EM.run do
36
39
  @push_topics.map do |topic|
37
- replay_id = Configuration.instance.replay_adapter.call(topic)
38
- client.subscribe topic.name, replay: replay_id.to_i do |message|
39
- replay_id = message.dig('event', 'replayId')
40
- Log.info "Message #{replay_id} received from topic #{topic.name}"
40
+ client.subscribe topic.name, replay: Configuration.instance.replay_adapter do |message|
41
+ Log.info "Message #{message.dig('event', 'replayId')} received from topic #{topic.name}"
41
42
  topic.handle message
42
- topic.id = replay_id
43
43
  end
44
44
  end
45
45
  end
@@ -1,3 +1,3 @@
1
1
  module SalesforceStreamer
2
- VERSION = '2.0.0.rc1'.freeze
2
+ VERSION = '2.2.0'.freeze
3
3
  end
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
14
14
 
15
15
  spec.metadata['homepage_uri'] = spec.homepage
16
16
  spec.metadata['source_code_uri'] = spec.homepage
17
+ spec.metadata['documentation_uri'] = 'https://www.rubydoc.info/gems/salesforce_streamer'
17
18
 
18
19
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
19
20
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(bin/|spec/|\.rub)}) }
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: salesforce_streamer
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.rc1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Serok
8
8
  - RenoFi Engineering Team
9
- autorequire:
9
+ autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2020-08-04 00:00:00.000000000 Z
12
+ date: 2020-11-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: dry-initializer
@@ -157,7 +157,7 @@ dependencies:
157
157
  - - ">="
158
158
  - !ruby/object:Gem::Version
159
159
  version: '0'
160
- description:
160
+ description:
161
161
  email:
162
162
  - scott@renofi.com
163
163
  - engineering@renofi.com
@@ -172,6 +172,7 @@ files:
172
172
  - ".github/ISSUE_TEMPLATE/story.md"
173
173
  - ".github/PULL_REQUEST_TEMPLATE.md"
174
174
  - ".github/workflows/auto-approve.yml"
175
+ - ".github/workflows/auto-merge.yml"
175
176
  - ".gitignore"
176
177
  - ".rspec"
177
178
  - ".travis.yml"
@@ -202,7 +203,8 @@ licenses:
202
203
  metadata:
203
204
  homepage_uri: https://github.com/renofi/salesforce_streamer
204
205
  source_code_uri: https://github.com/renofi/salesforce_streamer
205
- post_install_message:
206
+ documentation_uri: https://www.rubydoc.info/gems/salesforce_streamer
207
+ post_install_message:
206
208
  rdoc_options: []
207
209
  require_paths:
208
210
  - lib
@@ -213,12 +215,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
213
215
  version: '2.6'
214
216
  required_rubygems_version: !ruby/object:Gem::Requirement
215
217
  requirements:
216
- - - ">"
218
+ - - ">="
217
219
  - !ruby/object:Gem::Version
218
- version: 1.3.1
220
+ version: '0'
219
221
  requirements: []
220
- rubygems_version: 3.1.2
221
- signing_key:
222
+ rubygems_version: 3.1.4
223
+ signing_key:
222
224
  specification_version: 4
223
225
  summary: A wrapper around the Restforce Streaming API with a built-in PushTopic manager.
224
226
  test_files: []