event_store_client 1.1.0 → 1.1.5
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/lib/event_store_client/adapters/grpc/client.rb +4 -1
- data/lib/event_store_client/adapters/grpc/commands/command.rb +1 -1
- data/lib/event_store_client/adapters/grpc/commands/persistent_subscriptions/read.rb +5 -3
- data/lib/event_store_client/adapters/grpc/commands/projections/create.rb +5 -2
- data/lib/event_store_client/adapters/grpc/commands/projections/update.rb +2 -0
- data/lib/event_store_client/adapters/grpc/commands/streams/read.rb +4 -4
- data/lib/event_store_client/adapters/http.rb +1 -0
- data/lib/event_store_client/adapters/http/client.rb +4 -1
- data/lib/event_store_client/adapters/http/commands/persistent_subscriptions/read.rb +6 -3
- data/lib/event_store_client/adapters/http/commands/projections/create.rb +4 -1
- data/lib/event_store_client/adapters/http/commands/projections/update.rb +31 -0
- data/lib/event_store_client/adapters/http/commands/streams/read.rb +4 -3
- data/lib/event_store_client/adapters/in_memory.rb +4 -3
- data/lib/event_store_client/broker.rb +10 -1
- data/lib/event_store_client/catch_up_subscriptions.rb +13 -1
- data/lib/event_store_client/client.rb +6 -0
- data/lib/event_store_client/configuration.rb +2 -0
- data/lib/event_store_client/data_decryptor.rb +8 -7
- data/lib/event_store_client/mapper/default.rb +1 -1
- data/lib/event_store_client/mapper/encrypted.rb +12 -6
- data/lib/event_store_client/version.rb +1 -1
- metadata +21 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2624a6c8e08a686f5e307eccfb00ac9321eb5e2e32aed9093c0c67e8cb01b9e5
|
4
|
+
data.tar.gz: 0b4ff333a547924f54aa182e0bb1f821a7382db93c5d9304038c43a514ee6d3b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dfda05e2c763e85977c63a3b0e27034050b37c7ded273750b1aadec42e55fc459475c4a8d50167fe66952bb39c7145242ed017b5548abbece412beaa4e98d37a
|
7
|
+
data.tar.gz: ca27251198df7d78a9b60482ee8dfef7f8b6cfdbda08d3a36f0af1723ee487b85239d0d046a6d777e5c6e5161725faaa4b4fac6aa3b650460eb622a428dc0960
|
@@ -110,7 +110,10 @@ module EventStoreClient
|
|
110
110
|
# @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
|
111
111
|
#
|
112
112
|
def join_streams(name, streams)
|
113
|
-
Commands::Projections::Create.new.call(name, streams)
|
113
|
+
res = Commands::Projections::Create.new.call(name, streams)
|
114
|
+
return if res.success?
|
115
|
+
|
116
|
+
Commands::Projections::Update.new.call(name, streams)
|
114
117
|
end
|
115
118
|
|
116
119
|
# @api private
|
@@ -12,7 +12,7 @@ module EventStoreClient
|
|
12
12
|
def self.inherited(klass)
|
13
13
|
super
|
14
14
|
klass.class_eval do
|
15
|
-
include Dry::Monads[:result]
|
15
|
+
include Dry::Monads[:try, :result]
|
16
16
|
|
17
17
|
def self.use_request(request_klass)
|
18
18
|
CommandRegistrar.register_request(self, request: request_klass)
|
@@ -38,16 +38,17 @@ module EventStoreClient
|
|
38
38
|
|
39
39
|
requests = [request.new(options: opts)] # please notice that it's an array. Should be?
|
40
40
|
|
41
|
+
skip_decryption = options[:skip_decryption] || false
|
41
42
|
service.read(requests, metadata: metadata).each do |res|
|
42
43
|
next if res.subscription_confirmation
|
43
|
-
yield deserialize_event(res.event.event) if block_given?
|
44
|
+
yield deserialize_event(res.event.event, skip_decryption: skip_decryption) if block_given?
|
44
45
|
end
|
45
46
|
Success()
|
46
47
|
end
|
47
48
|
|
48
49
|
private
|
49
50
|
|
50
|
-
def deserialize_event(entry)
|
51
|
+
def deserialize_event(entry, skip_decryption: false)
|
51
52
|
id = entry.id.string
|
52
53
|
id = SecureRandom.uuid if id.nil? || id.empty?
|
53
54
|
|
@@ -65,7 +66,8 @@ module EventStoreClient
|
|
65
66
|
type: entry.metadata['type'],
|
66
67
|
data: data,
|
67
68
|
metadata: metadata
|
68
|
-
)
|
69
|
+
),
|
70
|
+
skip_decryption: skip_decryption
|
69
71
|
)
|
70
72
|
end
|
71
73
|
end
|
@@ -33,8 +33,11 @@ module EventStoreClient
|
|
33
33
|
}
|
34
34
|
}
|
35
35
|
|
36
|
-
|
37
|
-
|
36
|
+
res = Try do
|
37
|
+
service.create(request.new(options: options), metadata: metadata)
|
38
|
+
end
|
39
|
+
|
40
|
+
res.error? ? res.to_result : Success()
|
38
41
|
rescue ::GRPC::Unknown => e
|
39
42
|
Failure(:conflict) if e.message.include?('Conflict')
|
40
43
|
end
|
@@ -43,10 +43,10 @@ module EventStoreClient
|
|
43
43
|
opts[:stream][:revision] = options[:start]
|
44
44
|
end
|
45
45
|
|
46
|
+
skip_decryption = options[:skip_decryption] || false
|
46
47
|
events = service.read(request.new(options: opts), metadata: metadata).map do |res|
|
47
48
|
raise StreamNotFound if res.stream_not_found
|
48
|
-
|
49
|
-
deserialize_event(res.event.event)
|
49
|
+
deserialize_event(res.event.event, skip_decryption: skip_decryption)
|
50
50
|
end
|
51
51
|
Success(events)
|
52
52
|
rescue StreamNotFound
|
@@ -55,7 +55,7 @@ module EventStoreClient
|
|
55
55
|
|
56
56
|
private
|
57
57
|
|
58
|
-
def deserialize_event(entry)
|
58
|
+
def deserialize_event(entry, skip_decryption: false)
|
59
59
|
data = (entry.data.nil? || entry.data.empty?) ? '{}' : entry.data
|
60
60
|
|
61
61
|
metadata =
|
@@ -71,7 +71,7 @@ module EventStoreClient
|
|
71
71
|
metadata: metadata
|
72
72
|
)
|
73
73
|
|
74
|
-
config.mapper.deserialize(event)
|
74
|
+
config.mapper.deserialize(event, skip_decryption: skip_decryption)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
end
|
@@ -6,6 +6,7 @@ require 'event_store_client/adapters/http/commands/persistent_subscriptions/crea
|
|
6
6
|
require 'event_store_client/adapters/http/commands/persistent_subscriptions/read'
|
7
7
|
|
8
8
|
require 'event_store_client/adapters/http/commands/projections/create'
|
9
|
+
require 'event_store_client/adapters/http/commands/projections/update'
|
9
10
|
|
10
11
|
require 'event_store_client/adapters/http/commands/streams/append'
|
11
12
|
require 'event_store_client/adapters/http/commands/streams/delete'
|
@@ -137,7 +137,10 @@ module EventStoreClient
|
|
137
137
|
# @return Dry::Monads::Result::Success or Dry::Monads::Result::Failure
|
138
138
|
#
|
139
139
|
def join_streams(name, streams, options: {})
|
140
|
-
Commands::Projections::Create.new(connection).call(name, streams, options: options)
|
140
|
+
res = Commands::Projections::Create.new(connection).call(name, streams, options: options)
|
141
|
+
return res if res.success?
|
142
|
+
|
143
|
+
Commands::Projections::Update.new(connection).call(name, streams, options: options)
|
141
144
|
end
|
142
145
|
|
143
146
|
# @api private
|
@@ -28,16 +28,19 @@ module EventStoreClient
|
|
28
28
|
|
29
29
|
ack_info = body['links'].find { |link| link['relation'] == 'ackAll' }
|
30
30
|
return { events: [] } unless ack_info
|
31
|
+
|
32
|
+
skip_decryption = options[:skip_decryption] || false
|
31
33
|
body['entries'].map do |entry|
|
32
|
-
yield deserialize_event(entry)
|
34
|
+
yield deserialize_event(entry, skip_decryption: skip_decryption)
|
33
35
|
end
|
36
|
+
|
34
37
|
Ack.new(connection).call(ack_info['uri'])
|
35
38
|
Success()
|
36
39
|
end
|
37
40
|
|
38
41
|
private
|
39
42
|
|
40
|
-
def deserialize_event(entry)
|
43
|
+
def deserialize_event(entry, skip_decryption: false)
|
41
44
|
event = EventStoreClient::Event.new(
|
42
45
|
id: entry['eventId'],
|
43
46
|
title: entry['title'],
|
@@ -46,7 +49,7 @@ module EventStoreClient
|
|
46
49
|
metadata: entry['isMetaData'] ? entry['metaData'] : '{}'
|
47
50
|
)
|
48
51
|
|
49
|
-
config.mapper.deserialize(event)
|
52
|
+
config.mapper.deserialize(event, skip_decryption: skip_decryption)
|
50
53
|
rescue EventStoreClient::DeserializedEvent::InvalidDataError
|
51
54
|
event
|
52
55
|
end
|
@@ -16,12 +16,15 @@ module EventStoreClient
|
|
16
16
|
})
|
17
17
|
STRING
|
18
18
|
|
19
|
-
|
19
|
+
|
20
|
+
res = connection.call(
|
20
21
|
:post,
|
21
22
|
"/projections/continuous?name=#{name}&type=js&enabled=yes&emit=true&trackemittedstreams=true", # rubocop:disable Metrics/LineLength
|
22
23
|
body: data,
|
23
24
|
headers: {}
|
24
25
|
)
|
26
|
+
|
27
|
+
(200...300).cover?(res.status) ? Success() : Failure(res)
|
25
28
|
end
|
26
29
|
end
|
27
30
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module EventStoreClient
|
4
|
+
module HTTP
|
5
|
+
module Commands
|
6
|
+
module Projections
|
7
|
+
class Update < Command
|
8
|
+
def call(name, streams, options: {})
|
9
|
+
data =
|
10
|
+
<<~STRING
|
11
|
+
fromStreams(#{streams})
|
12
|
+
.when({
|
13
|
+
$any: function(s,e) {
|
14
|
+
linkTo("#{name}", e)
|
15
|
+
}
|
16
|
+
})
|
17
|
+
STRING
|
18
|
+
res = connection.call(
|
19
|
+
:put,
|
20
|
+
"/projection/#{name}/query?type=js&enabled=yes&emit=true&trackemittedstreams=true", # rubocop:disable Metrics/LineLength
|
21
|
+
body: data,
|
22
|
+
headers: {}
|
23
|
+
)
|
24
|
+
|
25
|
+
(200...300).cover?(res.status) ? Success() : Failure(res)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -23,8 +23,9 @@ module EventStoreClient
|
|
23
23
|
|
24
24
|
return Failure(:stream_not_found) unless response.success? || response.status == 404
|
25
25
|
return Failure(:connection_failed) if response.body.nil? || response.body.empty?
|
26
|
+
skip_decryption = options[:skip_decryption] || false
|
26
27
|
entries = JSON.parse(response.body)['entries'].map do |entry|
|
27
|
-
deserialize_event(entry)
|
28
|
+
deserialize_event(entry, skip_decryption: skip_decryption)
|
28
29
|
end.reverse
|
29
30
|
Success(entries)
|
30
31
|
rescue Faraday::ConnectionFailed
|
@@ -33,7 +34,7 @@ module EventStoreClient
|
|
33
34
|
|
34
35
|
private
|
35
36
|
|
36
|
-
def deserialize_event(entry)
|
37
|
+
def deserialize_event(entry, skip_decryption: false)
|
37
38
|
event = EventStoreClient::Event.new(
|
38
39
|
id: entry['eventId'],
|
39
40
|
title: entry['title'],
|
@@ -42,7 +43,7 @@ module EventStoreClient
|
|
42
43
|
metadata: entry['isMetaData'] ? entry['metaData'] : '{}'
|
43
44
|
)
|
44
45
|
|
45
|
-
config.mapper.deserialize(event)
|
46
|
+
config.mapper.deserialize(event, skip_decryption: skip_decryption)
|
46
47
|
end
|
47
48
|
end
|
48
49
|
end
|
@@ -46,8 +46,9 @@ module EventStoreClient
|
|
46
46
|
res = Response.new(response.to_json, 200)
|
47
47
|
|
48
48
|
return [] if res.body.nil? || res.body.empty?
|
49
|
+
skip_decryption = options[:skip_decryption] || false
|
49
50
|
events = JSON.parse(res.body)['entries'].map do |entry|
|
50
|
-
deserialize_event(entry)
|
51
|
+
deserialize_event(entry, skip_decryption: skip_decryption)
|
51
52
|
end.reverse
|
52
53
|
Dry::Monads::Success(events)
|
53
54
|
end
|
@@ -127,7 +128,7 @@ module EventStoreClient
|
|
127
128
|
end
|
128
129
|
end
|
129
130
|
|
130
|
-
def deserialize_event(entry)
|
131
|
+
def deserialize_event(entry, skip_decryption: false)
|
131
132
|
event = EventStoreClient::Event.new(
|
132
133
|
id: entry['eventId'],
|
133
134
|
title: entry['title'],
|
@@ -136,7 +137,7 @@ module EventStoreClient
|
|
136
137
|
metadata: entry['isMetaData'] ? entry['metaData'] : '{}'
|
137
138
|
)
|
138
139
|
|
139
|
-
mapper.deserialize(event)
|
140
|
+
mapper.deserialize(event, skip_decryption: skip_decryption)
|
140
141
|
end
|
141
142
|
end
|
142
143
|
end
|
@@ -10,6 +10,14 @@ module EventStoreClient
|
|
10
10
|
# main app process (useful for debugging)
|
11
11
|
#
|
12
12
|
def call(subscriptions, wait: false)
|
13
|
+
Signal.trap('TERM') do
|
14
|
+
Thread.new { logger&.info('Broker: TERM Signal has been received') }
|
15
|
+
threads.each do |thread|
|
16
|
+
thread.thread_variable_set(:terminate, true)
|
17
|
+
end
|
18
|
+
Thread.new { logger&.info('Broker: Terminate variable for subscription threads set') }
|
19
|
+
end
|
20
|
+
|
13
21
|
subscriptions.each do |subscription|
|
14
22
|
threads << Thread.new do
|
15
23
|
subscriptions.listen(subscription)
|
@@ -20,12 +28,13 @@ module EventStoreClient
|
|
20
28
|
|
21
29
|
private
|
22
30
|
|
23
|
-
attr_reader :connection
|
31
|
+
attr_reader :connection, :logger
|
24
32
|
attr_accessor :threads
|
25
33
|
|
26
34
|
def initialize(connection:)
|
27
35
|
@connection = connection
|
28
36
|
@threads = []
|
37
|
+
@logger = EventStoreClient.config.logger
|
29
38
|
end
|
30
39
|
end
|
31
40
|
end
|
@@ -34,6 +34,13 @@ module EventStoreClient
|
|
34
34
|
next unless event
|
35
35
|
|
36
36
|
subscription.subscriber.call(event)
|
37
|
+
|
38
|
+
if Thread.current.thread_variable_get(:terminate)
|
39
|
+
msg =
|
40
|
+
"CatchUpSubscriptions: Terminating subscription listener for #{subscription.subscriber}"
|
41
|
+
logger&.info(msg)
|
42
|
+
break
|
43
|
+
end
|
37
44
|
rescue StandardError
|
38
45
|
subscription.position = old_position
|
39
46
|
subscription_store.update_position(subscription)
|
@@ -45,14 +52,19 @@ module EventStoreClient
|
|
45
52
|
subscription_store.clean_unused(subscriptions.map(&:name))
|
46
53
|
end
|
47
54
|
|
55
|
+
def reset
|
56
|
+
subscription_store.reset(subscriptions)
|
57
|
+
end
|
58
|
+
|
48
59
|
private
|
49
60
|
|
50
|
-
attr_reader :connection, :subscriptions, :subscription_store
|
61
|
+
attr_reader :connection, :subscriptions, :subscription_store, :logger
|
51
62
|
|
52
63
|
def initialize(connection:, subscription_store:)
|
53
64
|
@connection = connection
|
54
65
|
@subscription_store = subscription_store
|
55
66
|
@subscriptions = []
|
67
|
+
@logger = EventStoreClient.config.logger
|
56
68
|
end
|
57
69
|
|
58
70
|
def confirmation?(event_data)
|
@@ -33,6 +33,12 @@ module EventStoreClient
|
|
33
33
|
@subscriptions.create_or_load(subscriber, filter: filter)
|
34
34
|
end
|
35
35
|
|
36
|
+
def reset_subscriptions
|
37
|
+
return unless @subscriptions.respond_to?(:reset)
|
38
|
+
|
39
|
+
@subscriptions.reset
|
40
|
+
end
|
41
|
+
|
36
42
|
def listen(wait: false)
|
37
43
|
broker.call(@subscriptions, wait: wait)
|
38
44
|
end
|
@@ -9,28 +9,28 @@ module EventStoreClient
|
|
9
9
|
KeyNotFoundError = Class.new(StandardError)
|
10
10
|
|
11
11
|
def call
|
12
|
-
return
|
12
|
+
return encrypted_data if encryption_metadata.empty?
|
13
13
|
|
14
14
|
decrypt_attributes(
|
15
15
|
key: find_key(encryption_metadata['key']),
|
16
|
-
data:
|
16
|
+
data: encrypted_data,
|
17
17
|
attributes: encryption_metadata['attributes']
|
18
18
|
)
|
19
19
|
end
|
20
20
|
|
21
|
-
attr_reader :decrypted_data, :encryption_metadata
|
22
|
-
|
23
21
|
private
|
24
22
|
|
25
|
-
attr_reader :key_repository
|
23
|
+
attr_reader :key_repository, :encryption_metadata, :encrypted_data
|
26
24
|
|
27
25
|
def initialize(data:, schema:, repository:)
|
28
|
-
@
|
26
|
+
@encrypted_data = deep_dup(data).transform_keys!(&:to_s)
|
29
27
|
@key_repository = repository
|
30
28
|
@encryption_metadata = schema&.transform_keys(&:to_s) || {}
|
31
29
|
end
|
32
30
|
|
33
31
|
def decrypt_attributes(key:, data:, attributes: {}) # rubocop:disable Lint/UnusedMethodArgument
|
32
|
+
return data unless key
|
33
|
+
|
34
34
|
res = key_repository.decrypt(key: key, message: data['es_encrypted'])
|
35
35
|
return data if res.failure?
|
36
36
|
|
@@ -42,6 +42,7 @@ module EventStoreClient
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def deep_dup(hash)
|
45
|
+
return hash unless hash.instance_of?(Hash)
|
45
46
|
dupl = hash.dup
|
46
47
|
dupl.each { |k, v| dupl[k] = v.instance_of?(Hash) ? deep_dup(v) : v }
|
47
48
|
dupl
|
@@ -53,8 +54,8 @@ module EventStoreClient
|
|
53
54
|
key_repository.find(identifier).value!
|
54
55
|
rescue StandardError => e
|
55
56
|
config.error_handler&.call(e)
|
57
|
+
nil
|
56
58
|
end
|
57
|
-
raise KeyNotFoundError unless key
|
58
59
|
|
59
60
|
key
|
60
61
|
end
|
@@ -49,14 +49,20 @@ module EventStoreClient
|
|
49
49
|
# which key should be used as an identifier.
|
50
50
|
# *Returns*: Specific event class with all data decrypted
|
51
51
|
|
52
|
-
def deserialize(event)
|
52
|
+
def deserialize(event, skip_decryption: false)
|
53
53
|
metadata = serializer.deserialize(event.metadata)
|
54
54
|
encryption_schema = serializer.deserialize(event.metadata)['encryption']
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
55
|
+
|
56
|
+
decrypted_data =
|
57
|
+
if skip_decryption
|
58
|
+
serializer.deserialize(event.data)
|
59
|
+
else
|
60
|
+
EventStoreClient::DataDecryptor.new(
|
61
|
+
data: serializer.deserialize(event.data),
|
62
|
+
schema: encryption_schema,
|
63
|
+
repository: key_repository
|
64
|
+
).call
|
65
|
+
end
|
60
66
|
|
61
67
|
event_class =
|
62
68
|
begin
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: event_store_client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sebastian Wilgosz
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-06-
|
11
|
+
date: 2021-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-configurable
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: 0.2.8
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.14'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.14'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: rspec
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -199,6 +213,7 @@ files:
|
|
199
213
|
- lib/event_store_client/adapters/http/commands/persistent_subscriptions/create.rb
|
200
214
|
- lib/event_store_client/adapters/http/commands/persistent_subscriptions/read.rb
|
201
215
|
- lib/event_store_client/adapters/http/commands/projections/create.rb
|
216
|
+
- lib/event_store_client/adapters/http/commands/projections/update.rb
|
202
217
|
- lib/event_store_client/adapters/http/commands/streams/append.rb
|
203
218
|
- lib/event_store_client/adapters/http/commands/streams/delete.rb
|
204
219
|
- lib/event_store_client/adapters/http/commands/streams/link_to.rb
|
@@ -232,7 +247,7 @@ licenses:
|
|
232
247
|
- MIT
|
233
248
|
metadata:
|
234
249
|
allowed_push_host: https://rubygems.org
|
235
|
-
post_install_message:
|
250
|
+
post_install_message:
|
236
251
|
rdoc_options: []
|
237
252
|
require_paths:
|
238
253
|
- lib
|
@@ -247,8 +262,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
247
262
|
- !ruby/object:Gem::Version
|
248
263
|
version: '0'
|
249
264
|
requirements: []
|
250
|
-
rubygems_version: 3.
|
251
|
-
signing_key:
|
265
|
+
rubygems_version: 3.1.4
|
266
|
+
signing_key:
|
252
267
|
specification_version: 4
|
253
268
|
summary: Ruby integration for https://eventstore.org
|
254
269
|
test_files: []
|