hyper-operation 1.0.alpha1.2 → 1.0.alpha1.7

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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -0
  3. data/.travis.yml +1 -0
  4. data/hyper-operation.gemspec +6 -4
  5. data/lib/hyper-operation.rb +4 -1
  6. data/lib/hyper-operation/api.rb +6 -2
  7. data/lib/hyper-operation/async_sleep.rb +23 -0
  8. data/lib/hyper-operation/exception.rb +29 -3
  9. data/lib/hyper-operation/promise.rb +32 -2
  10. data/lib/hyper-operation/railway/dispatcher.rb +0 -1
  11. data/lib/hyper-operation/railway/run.rb +57 -48
  12. data/lib/hyper-operation/railway/validations.rb +9 -2
  13. data/lib/hyper-operation/server_op.rb +31 -9
  14. data/lib/hyper-operation/transport/client_drivers.rb +45 -11
  15. data/lib/hyper-operation/transport/connection.rb +58 -136
  16. data/lib/hyper-operation/transport/connection_adapter/active_record.rb +113 -0
  17. data/lib/hyper-operation/transport/connection_adapter/active_record/auto_create.rb +26 -0
  18. data/lib/hyper-operation/transport/connection_adapter/active_record/connection.rb +47 -0
  19. data/lib/hyper-operation/transport/connection_adapter/active_record/queued_message.rb +42 -0
  20. data/lib/hyper-operation/transport/connection_adapter/redis.rb +94 -0
  21. data/lib/hyper-operation/transport/connection_adapter/redis/connection.rb +85 -0
  22. data/lib/hyper-operation/transport/connection_adapter/redis/queued_message.rb +34 -0
  23. data/lib/hyper-operation/transport/connection_adapter/redis/redis_record.rb +158 -0
  24. data/lib/hyper-operation/transport/hyperstack.rb +15 -2
  25. data/lib/hyper-operation/transport/hyperstack_controller.rb +6 -2
  26. data/lib/hyper-operation/transport/policy.rb +16 -26
  27. data/lib/hyper-operation/transport/policy_diagnostics.rb +106 -0
  28. data/lib/hyper-operation/version.rb +1 -1
  29. metadata +79 -38
  30. data/Gemfile.lock +0 -385
  31. data/lib/hyper-operation/delay_and_interval.rb +0 -9
@@ -16,7 +16,7 @@ module Hyperstack
16
16
  # config.eager_load_paths += %W(#{config.root}/app/hyperstack/models)
17
17
  # config.autoload_paths += %W(#{config.root}/app/hyperstack/models)
18
18
  # config.assets.paths << ::Rails.root.join('app', 'hyperstack').to_s
19
- config.after_initialize { Connection.build_tables }
19
+ config.after_initialize { Connection.build_tables if Connection.build_tables? }
20
20
  end
21
21
  Object.send(:remove_const, :Application) if @fake_application_defined
22
22
  @fake_application_defined = false
@@ -59,11 +59,21 @@ module Hyperstack
59
59
  end
60
60
  end
61
61
 
62
+ define_setting(:send_to_server_timeout, 10)
63
+
62
64
  define_setting :opts, {}
63
65
  define_setting :channel_prefix, 'synchromesh'
64
66
  define_setting :client_logging, true
65
67
  define_setting :connect_session, true
66
68
 
69
+ define_setting(:connection, { adapter: :active_record }) do |connection|
70
+ if connection[:adapter] == :redis
71
+ require 'redis'
72
+
73
+ connection[:redis_url] ||= 'redis://127.0.0.1:6379/hyperstack'
74
+ end
75
+ end
76
+
67
77
  def self.app_id
68
78
  opts[:app_id] || Pusher.app_id if transport == :pusher
69
79
  end
@@ -163,7 +173,10 @@ module Hyperstack
163
173
  request.body = {
164
174
  channel: channel, data: data, salt: salt, authorization: authorization
165
175
  }.to_json
166
- http.request(request)
176
+ Timeout::timeout(Hyperstack.send_to_server_timeout) { http.request(request) }
177
+ rescue Timeout::Error
178
+ puts "\n********* FAILED TO RECEIVE RESPONSE FROM SERVER WITHIN #{Hyperstack.send_to_server_timeout} SECONDS. CHANGES WILL NOT BE SYNCED ************\n"
179
+ raise 'no server running'
167
180
  end
168
181
 
169
182
  def self.dispatch(data)
@@ -11,6 +11,10 @@ module Hyperstack
11
11
  end
12
12
  end if defined? ::WebConsole::Middleware
13
13
 
14
+
15
+ # The purpose of this is to prevent massive amounts of logging
16
+ # if using simple polling. If polling is on then only actual messages
17
+ # with content will be shown, other wise the log message is dropped.
14
18
  module ::Rails
15
19
  module Rack
16
20
  class Logger < ActiveSupport::LogSubscriber
@@ -141,7 +145,7 @@ module Hyperstack
141
145
  end
142
146
 
143
147
  def execute_remote
144
- parsed_params = JSON.parse(params[:json]).symbolize_keys
148
+ parsed_params = JSON.parse(params[:hyperstack_secured_json]).symbolize_keys
145
149
  render ServerOp.run_from_client(
146
150
  :acting_user,
147
151
  self,
@@ -153,7 +157,7 @@ module Hyperstack
153
157
  def execute_remote_api
154
158
  params.require(:params).permit!
155
159
  parsed_params = params[:params].to_h.symbolize_keys
156
- raise AccessViolation unless parsed_params[:authorization]
160
+ raise AccessViolation.new(:illegal_remote_api_call) unless parsed_params[:authorization]
157
161
  render ServerOp.run_from_client(:authorization, self, params[:operation], parsed_params)
158
162
  end
159
163
 
@@ -21,7 +21,7 @@ module Hyperstack
21
21
  EXPOSED_METHODS = [
22
22
  :regulate_class_connection, :always_allow_connection, :regulate_instance_connections,
23
23
  :regulate_all_broadcasts, :regulate_broadcast,
24
- :dispatch_to, :regulate_dispatches_from, :always_dispatch_from,
24
+ :regulate_dispatches_from, :always_dispatch_from,
25
25
  :allow_change, :allow_create, :allow_read, :allow_update, :allow_destroy
26
26
  ]
27
27
 
@@ -58,21 +58,6 @@ module Hyperstack
58
58
  regulate_dispatches_from(*args) { true }
59
59
  end
60
60
 
61
- def dispatch_to(*args, &regulation)
62
- actual_klass = if regulated_klass.is_a?(Class)
63
- regulated_klass
64
- else
65
- begin
66
- regulated_klass.constantize
67
- rescue NameError
68
- nil
69
- end
70
- end
71
- raise 'you can only dispatch_to Operation classes' unless actual_klass.respond_to? :dispatch_to
72
- actual_klass.dispatch_to(actual_klass)
73
- actual_klass.dispatch_to(*args, &regulation)
74
- end
75
-
76
61
  CHANGE_POLICIES = [:create, :update, :destroy]
77
62
 
78
63
  def self.allow_policy(policy, method)
@@ -343,9 +328,9 @@ module Hyperstack
343
328
  regulations[instance].regulations.each do |regulation|
344
329
  instance.instance_exec wrap_policy(policy, regulation), &regulation
345
330
  end
346
- if policy.has_unassigned_sets?
347
- raise "#{instance.class.name} instance broadcast policy not sent to any channel"
348
- end
331
+ return if policy.has_to_been_called?
332
+
333
+ raise "#{instance.class.name} instance broadcast policy not sent to any channel"
349
334
  end
350
335
  end
351
336
 
@@ -379,8 +364,7 @@ module Hyperstack
379
364
  end
380
365
 
381
366
  def self.raise_operation_access_violation(message, details)
382
- Hyperstack.on_error(Hyperstack::AccessViolation, message, details)
383
- raise Hyperstack::AccessViolation
367
+ raise Hyperstack::AccessViolation.new(message, details)
384
368
  end
385
369
 
386
370
  def self.regulate_connection(acting_user, channel_string)
@@ -406,16 +390,17 @@ module Hyperstack
406
390
  internal_policy.broadcast &block
407
391
  end
408
392
 
409
- def initialize(obj, attribute_names, available_channels)
393
+ def initialize(obj, attribute_names, available_channels = :all)
410
394
  @obj = obj
411
- attribute_names = attribute_names.map(&:to_sym).to_set
395
+ @attribute_names = attribute_names.map(&:to_sym).to_set
412
396
  @unassigned_send_sets = []
413
- @channel_sets = Hash.new { |hash, key| hash[key] = attribute_names }
397
+ @channel_sets = Hash.new { |hash, key| hash[key] = @attribute_names }
414
398
  @available_channels = available_channels
415
399
  end
416
400
 
417
401
  def channel_available?(channel)
418
- channel && @available_channels.include?(channel_to_string(channel))
402
+ return false unless channel
403
+ @available_channels == :all || @available_channels.include?(channel_to_string(channel))
419
404
  end
420
405
 
421
406
  def id
@@ -440,12 +425,17 @@ module Hyperstack
440
425
  end
441
426
 
442
427
  def send_set_to(send_set, channels)
428
+ @to_has_been_called = true
443
429
  channels.flatten(1).each do |channel|
444
430
  merge_set(send_set, channel) if channel_available? channel
445
431
  @unassigned_send_sets.delete(send_set)
446
432
  end
447
433
  end
448
434
 
435
+ def has_to_been_called?
436
+ !has_unassigned_sets? || @to_has_been_called
437
+ end
438
+
449
439
  def merge_set(send_set, channel)
450
440
  return unless channel
451
441
  channel = channel.name if channel.is_a?(Class) && channel.name
@@ -482,7 +472,7 @@ module Hyperstack
482
472
 
483
473
  def send_message(header, channel, attribute_set, &block)
484
474
  record = filter(@obj.react_serializer, attribute_set)
485
- previous_changes = filter(@obj.previous_changes, attribute_set)
475
+ previous_changes = filter(@obj.saved_changes, attribute_set)
486
476
  return if record.empty? && previous_changes.empty?
487
477
  message = header.merge(
488
478
  channel: channel_to_string(channel),
@@ -0,0 +1,106 @@
1
+ module Hyperstack
2
+ class ClassConnectionRegulation
3
+ def self.connections(acting_user)
4
+ regulations.collect do |channel, regulation|
5
+ status = regulation.connectable?(acting_user) ? :allowed : :denied
6
+ { type: :class, owner: channel, channel: InternalPolicy.channel_to_string(channel), auto_connect: !regulation.auto_connect_disabled?, status: status }
7
+ end
8
+ end
9
+ end
10
+
11
+ class InstanceConnectionRegulation
12
+ def self.connections(acting_user)
13
+ regulations.collect do |channel, regulation|
14
+ regulation.connectable_to(acting_user, false).collect do |obj|
15
+ { type: :instance, owner: channel, channel: InternalPolicy.channel_to_string(obj), auto_connect: !regulation.auto_connect_disabled?, status: :allowed }
16
+ end
17
+ end.flatten(1)
18
+ end
19
+ end
20
+
21
+ class InternalPolicy
22
+ def attribute_dump(acting_user)
23
+ # dump[channel]['@channel_status'] -> [owner, type, auto_connect, falsy/no connection/allowed]
24
+ # dump[channel][attribute] -> 'no connection/no channel/no policy/allowed'
25
+ dump = Hash.new { |h, k| h[k] = Hash.new }
26
+ connections = ClassConnectionRegulation.connections(acting_user) +
27
+ InstanceConnectionRegulation.connections(acting_user)
28
+ connections.each do |status|
29
+ status[:status] = 'allowed' if status[:status]
30
+ status[:status] ||= 'no connection'
31
+ dump[status[:channel]]['@channel_status'] = status
32
+ end
33
+ @channel_sets.each do |channel, attribute_set|
34
+ channel = InternalPolicy.channel_to_string(channel)
35
+ attribute_set.each do |attribute|
36
+ dump[channel]['@channel_status'] ||= { type: 'no channel' }
37
+ dump[channel][attribute] = dump[channel]['@channel_status'][:status] || 'no channel'
38
+ end
39
+ end
40
+ dump.each_key do |channel|
41
+ @attribute_names.each do |attribute|
42
+ dump[channel][attribute] ||= 'no policy'
43
+ end
44
+ end
45
+ dump
46
+ end
47
+ end
48
+
49
+ module PolicyDiagnostics
50
+ def self.policy_dump_hash(model, acting_user)
51
+ internal_policy = InternalPolicy.new(model, model.attribute_names, :all)
52
+ ChannelBroadcastRegulation.broadcast(internal_policy)
53
+ InstanceBroadcastRegulation.broadcast(model, internal_policy)
54
+ internal_policy.attribute_dump(acting_user)
55
+ end
56
+
57
+ def self.policy_dump_for(model, acting_user)
58
+ dump = policy_dump_hash(model, acting_user)
59
+ attributes = model.attribute_names.map(&:to_sym)
60
+ acting_user_channel = InternalPolicy.channel_to_string(acting_user) if acting_user
61
+ pastel = Pastel.new
62
+ channels = dump.keys.collect do |channel|
63
+ c = channel == acting_user_channel ? "* #{channel} *" : channel
64
+ if dump[channel]['@channel_status'][:status] != 'allowed'
65
+ pastel.red(c)
66
+ elsif channel == acting_user_channel
67
+ pastel.blue(c)
68
+ else
69
+ c
70
+ end
71
+ end
72
+ table = TTY::Table.new header: [''] + channels
73
+ types = dump.keys.collect do |channel|
74
+ type = dump[channel]['@channel_status'][:type]
75
+ type = pastel.red(type) if type == 'no policy'
76
+ type
77
+ end
78
+ table << ['type'] + types
79
+ table << ['auto connect'] + dump.keys.collect { |channel| dump[channel]['@channel_status'][:auto_connect] }
80
+ table << ['status'] + dump.keys.collect { |channel| dump[channel]['@channel_status'][:status] }
81
+ attributes.each do |attribute|
82
+ allowed = false
83
+ statuses = dump.keys.collect do |channel|
84
+ status = dump[channel][attribute]
85
+ if status == 'allowed'
86
+ allowed = true
87
+ status
88
+ else
89
+ pastel.red(status)
90
+ end
91
+ end
92
+ attribute = pastel.red(attribute) unless allowed
93
+ table << [attribute] + statuses
94
+ end
95
+ rendered = table.render(:unicode, indent: 4).split("\n")
96
+ rendered = rendered.insert(6, rendered[2]).join("\n")
97
+ model_string = "<##{model.class} id: #{model.id}>"
98
+ if acting_user
99
+ id = "id: #{acting_user.id}" if acting_user.respond_to? :id
100
+ acting_user_string = "by acting_user <##{acting_user.class} id: #{id}>"
101
+ end
102
+ " Attribute access policies for #{model_string} #{acting_user_string || 'with no acting_user'}:\n\n"\
103
+ "#{rendered}"
104
+ end
105
+ end
106
+ end
@@ -1,5 +1,5 @@
1
1
  module Hyperstack
2
2
  class Operation
3
- VERSION = '1.0.alpha1.2'
3
+ VERSION = '1.0.alpha1.7'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyper-operation
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.alpha1.2
4
+ version: 1.0.alpha1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mitch VanDuyn
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2018-11-16 00:00:00.000000000 Z
12
+ date: 2021-04-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -31,14 +31,14 @@ dependencies:
31
31
  requirements:
32
32
  - - '='
33
33
  - !ruby/object:Gem::Version
34
- version: 1.0.alpha1.2
34
+ version: 1.0.alpha1.7
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - '='
40
40
  - !ruby/object:Gem::Version
41
- version: 1.0.alpha1.2
41
+ version: 1.0.alpha1.7
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: mutations
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -67,6 +67,20 @@ dependencies:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
69
  version: 0.3.1
70
+ - !ruby/object:Gem::Dependency
71
+ name: tty-table
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
70
84
  - !ruby/object:Gem::Dependency
71
85
  name: bundler
72
86
  requirement: !ruby/object:Gem::Requirement
@@ -115,14 +129,14 @@ dependencies:
115
129
  requirements:
116
130
  - - '='
117
131
  - !ruby/object:Gem::Version
118
- version: 1.0.alpha1.2
132
+ version: 1.0.alpha1.7
119
133
  type: :development
120
134
  prerelease: false
121
135
  version_requirements: !ruby/object:Gem::Requirement
122
136
  requirements:
123
137
  - - '='
124
138
  - !ruby/object:Gem::Version
125
- version: 1.0.alpha1.2
139
+ version: 1.0.alpha1.7
126
140
  - !ruby/object:Gem::Dependency
127
141
  name: mysql2
128
142
  requirement: !ruby/object:Gem::Requirement
@@ -137,26 +151,6 @@ dependencies:
137
151
  - - ">="
138
152
  - !ruby/object:Gem::Version
139
153
  version: '0'
140
- - !ruby/object:Gem::Dependency
141
- name: opal
142
- requirement: !ruby/object:Gem::Requirement
143
- requirements:
144
- - - ">="
145
- - !ruby/object:Gem::Version
146
- version: 0.11.0
147
- - - "<"
148
- - !ruby/object:Gem::Version
149
- version: 0.12.0
150
- type: :development
151
- prerelease: false
152
- version_requirements: !ruby/object:Gem::Requirement
153
- requirements:
154
- - - ">="
155
- - !ruby/object:Gem::Version
156
- version: 0.11.0
157
- - - "<"
158
- - !ruby/object:Gem::Version
159
- version: 0.12.0
160
154
  - !ruby/object:Gem::Dependency
161
155
  name: opal-browser
162
156
  requirement: !ruby/object:Gem::Requirement
@@ -175,16 +169,22 @@ dependencies:
175
169
  name: opal-rails
176
170
  requirement: !ruby/object:Gem::Requirement
177
171
  requirements:
178
- - - "~>"
172
+ - - ">="
179
173
  - !ruby/object:Gem::Version
180
174
  version: 0.9.4
175
+ - - "<"
176
+ - !ruby/object:Gem::Version
177
+ version: '2.0'
181
178
  type: :development
182
179
  prerelease: false
183
180
  version_requirements: !ruby/object:Gem::Requirement
184
181
  requirements:
185
- - - "~>"
182
+ - - ">="
186
183
  - !ruby/object:Gem::Version
187
184
  version: 0.9.4
185
+ - - "<"
186
+ - !ruby/object:Gem::Version
187
+ version: '2.0'
188
188
  - !ruby/object:Gem::Dependency
189
189
  name: pry-rescue
190
190
  requirement: !ruby/object:Gem::Requirement
@@ -199,6 +199,20 @@ dependencies:
199
199
  - - ">="
200
200
  - !ruby/object:Gem::Version
201
201
  version: '0'
202
+ - !ruby/object:Gem::Dependency
203
+ name: pry-stack_explorer
204
+ requirement: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ type: :development
210
+ prerelease: false
211
+ version_requirements: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
202
216
  - !ruby/object:Gem::Dependency
203
217
  name: puma
204
218
  requirement: !ruby/object:Gem::Requirement
@@ -247,14 +261,20 @@ dependencies:
247
261
  requirements:
248
262
  - - ">="
249
263
  - !ruby/object:Gem::Version
250
- version: 4.0.0
264
+ version: 5.0.0
265
+ - - "<"
266
+ - !ruby/object:Gem::Version
267
+ version: '7.0'
251
268
  type: :development
252
269
  prerelease: false
253
270
  version_requirements: !ruby/object:Gem::Requirement
254
271
  requirements:
255
272
  - - ">="
256
273
  - !ruby/object:Gem::Version
257
- version: 4.0.0
274
+ version: 5.0.0
275
+ - - "<"
276
+ - !ruby/object:Gem::Version
277
+ version: '7.0'
258
278
  - !ruby/object:Gem::Dependency
259
279
  name: rake
260
280
  requirement: !ruby/object:Gem::Requirement
@@ -289,6 +309,20 @@ dependencies:
289
309
  - - "<"
290
310
  - !ruby/object:Gem::Version
291
311
  version: 2.5.0
312
+ - !ruby/object:Gem::Dependency
313
+ name: redis
314
+ requirement: !ruby/object:Gem::Requirement
315
+ requirements:
316
+ - - ">="
317
+ - !ruby/object:Gem::Version
318
+ version: '0'
319
+ type: :development
320
+ prerelease: false
321
+ version_requirements: !ruby/object:Gem::Requirement
322
+ requirements:
323
+ - - ">="
324
+ - !ruby/object:Gem::Version
325
+ version: '0'
292
326
  - !ruby/object:Gem::Dependency
293
327
  name: rspec-rails
294
328
  requirement: !ruby/object:Gem::Requirement
@@ -335,16 +369,16 @@ dependencies:
335
369
  name: sqlite3
336
370
  requirement: !ruby/object:Gem::Requirement
337
371
  requirements:
338
- - - ">="
372
+ - - "~>"
339
373
  - !ruby/object:Gem::Version
340
- version: '0'
374
+ version: 1.4.2
341
375
  type: :development
342
376
  prerelease: false
343
377
  version_requirements: !ruby/object:Gem::Requirement
344
378
  requirements:
345
- - - ">="
379
+ - - "~>"
346
380
  - !ruby/object:Gem::Version
347
- version: '0'
381
+ version: 1.4.2
348
382
  - !ruby/object:Gem::Dependency
349
383
  name: timecop
350
384
  requirement: !ruby/object:Gem::Requirement
@@ -370,13 +404,12 @@ files:
370
404
  - ".gitignore"
371
405
  - ".travis.yml"
372
406
  - Gemfile
373
- - Gemfile.lock
374
407
  - Rakefile
375
408
  - hyper-operation.gemspec
376
409
  - lib/hyper-operation.rb
377
410
  - lib/hyper-operation/api.rb
411
+ - lib/hyper-operation/async_sleep.rb
378
412
  - lib/hyper-operation/boot.rb
379
- - lib/hyper-operation/delay_and_interval.rb
380
413
  - lib/hyper-operation/engine.rb
381
414
  - lib/hyper-operation/exception.rb
382
415
  - lib/hyper-operation/filters/acting_user.rb
@@ -396,10 +429,19 @@ files:
396
429
  - lib/hyper-operation/transport/active_record.rb
397
430
  - lib/hyper-operation/transport/client_drivers.rb
398
431
  - lib/hyper-operation/transport/connection.rb
432
+ - lib/hyper-operation/transport/connection_adapter/active_record.rb
433
+ - lib/hyper-operation/transport/connection_adapter/active_record/auto_create.rb
434
+ - lib/hyper-operation/transport/connection_adapter/active_record/connection.rb
435
+ - lib/hyper-operation/transport/connection_adapter/active_record/queued_message.rb
436
+ - lib/hyper-operation/transport/connection_adapter/redis.rb
437
+ - lib/hyper-operation/transport/connection_adapter/redis/connection.rb
438
+ - lib/hyper-operation/transport/connection_adapter/redis/queued_message.rb
439
+ - lib/hyper-operation/transport/connection_adapter/redis/redis_record.rb
399
440
  - lib/hyper-operation/transport/hyperstack.rb
400
441
  - lib/hyper-operation/transport/hyperstack_controller.rb
401
442
  - lib/hyper-operation/transport/pluck.rb
402
443
  - lib/hyper-operation/transport/policy.rb
444
+ - lib/hyper-operation/transport/policy_diagnostics.rb
403
445
  - lib/hyper-operation/version.rb
404
446
  - lib/sources/hyperstack/pusher.js
405
447
  homepage: http://ruby-hyperstack.org
@@ -421,8 +463,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
421
463
  - !ruby/object:Gem::Version
422
464
  version: 1.3.1
423
465
  requirements: []
424
- rubyforge_project:
425
- rubygems_version: 2.7.8
466
+ rubygems_version: 3.0.8
426
467
  signing_key:
427
468
  specification_version: 4
428
469
  summary: HyperOperations are the swiss army knife of the Hyperstack