async-matrix 2.1.0-x86_64-linux → 3.0.0-x86_64-linux

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +33 -58
  3. data/lib/async/matrix/3.3/async_matrix_e2ee.so +0 -0
  4. data/lib/async/matrix/3.4/async_matrix_e2ee.so +0 -0
  5. data/lib/async/matrix/4.0/async_matrix_e2ee.so +0 -0
  6. data/lib/async/matrix/api/chain.rb +120 -94
  7. data/lib/async/matrix/api/concat.rb +28 -22
  8. data/lib/async/matrix/api/path_tree.rb +71 -44
  9. data/lib/async/matrix/api.rb +6 -1
  10. data/lib/async/matrix/auth_error.rb +20 -0
  11. data/lib/async/matrix/bad_json_error.rb +20 -0
  12. data/lib/async/matrix/client.rb +142 -110
  13. data/lib/async/matrix/config/vivify.rb +107 -0
  14. data/lib/async/matrix/config.rb +184 -0
  15. data/lib/async/matrix/content.rb +106 -0
  16. data/lib/async/matrix/double_puppet_client.rb +1 -1
  17. data/lib/async/matrix/error.rb +0 -27
  18. data/lib/async/matrix/{application_service/error_response.rb → error_response.rb} +10 -10
  19. data/lib/async/matrix/event.rb +197 -0
  20. data/lib/async/matrix/homeserver_error.rb +20 -0
  21. data/lib/async/matrix/invalid_endpoint_error.rb +20 -0
  22. data/lib/async/matrix/media_client.rb +46 -35
  23. data/lib/async/matrix/not_found_error.rb +20 -0
  24. data/lib/async/matrix/notifier.rb +7 -3
  25. data/lib/async/matrix/response_too_large_error.rb +20 -0
  26. data/lib/async/matrix/schema/registry.rb +367 -340
  27. data/lib/async/matrix/schema/validation_error.rb +221 -214
  28. data/lib/async/matrix/schema.rb +161 -161
  29. data/lib/async/matrix/version.rb +3 -3
  30. data/lib/async/matrix.rb +0 -7
  31. metadata +25 -133
  32. data/lib/async/discord/api/path_tree.rb +0 -127
  33. data/lib/async/discord/api.rb +0 -151
  34. data/lib/async/discord/client.rb +0 -283
  35. data/lib/async/discord/error.rb +0 -84
  36. data/lib/async/discord/gateway.rb +0 -359
  37. data/lib/async/discord.rb +0 -15
  38. data/lib/async/matrix/application_service/bot.rb +0 -232
  39. data/lib/async/matrix/application_service/config/schema/analytics.json +0 -21
  40. data/lib/async/matrix/application_service/config/schema/appservice.json +0 -82
  41. data/lib/async/matrix/application_service/config/schema/backfill.json +0 -91
  42. data/lib/async/matrix/application_service/config/schema/bridge.json +0 -209
  43. data/lib/async/matrix/application_service/config/schema/config.json +0 -61
  44. data/lib/async/matrix/application_service/config/schema/database.json +0 -38
  45. data/lib/async/matrix/application_service/config/schema/direct_media.json +0 -35
  46. data/lib/async/matrix/application_service/config/schema/double_puppet.json +0 -24
  47. data/lib/async/matrix/application_service/config/schema/encryption.json +0 -164
  48. data/lib/async/matrix/application_service/config/schema/homeserver.json +0 -58
  49. data/lib/async/matrix/application_service/config/schema/logging.json +0 -50
  50. data/lib/async/matrix/application_service/config/schema/management_room_texts.json +0 -25
  51. data/lib/async/matrix/application_service/config/schema/matrix.json +0 -45
  52. data/lib/async/matrix/application_service/config/schema/permissions.json +0 -54
  53. data/lib/async/matrix/application_service/config/schema/provisioning.json +0 -23
  54. data/lib/async/matrix/application_service/config/schema/public_media.json +0 -39
  55. data/lib/async/matrix/application_service/config/schema/relay.json +0 -43
  56. data/lib/async/matrix/application_service/config/vivify.rb +0 -109
  57. data/lib/async/matrix/application_service/config.rb +0 -225
  58. data/lib/async/matrix/application_service/dispatcher.rb +0 -185
  59. data/lib/async/matrix/application_service/event.rb +0 -285
  60. data/lib/async/matrix/application_service/server.rb +0 -430
  61. data/lib/async/matrix/application_service/transaction.rb +0 -66
  62. data/lib/async/matrix/application_service/transaction_handler.rb +0 -185
  63. data/lib/async/matrix/application_service/transaction_store.rb +0 -80
  64. data/lib/async/matrix/bridge/discord/db/connection.rb +0 -141
  65. data/lib/async/matrix/bridge/discord/db/file.rb +0 -118
  66. data/lib/async/matrix/bridge/discord/db/guild.rb +0 -120
  67. data/lib/async/matrix/bridge/discord/db/message.rb +0 -160
  68. data/lib/async/matrix/bridge/discord/db/migrations/001_create_users.rb +0 -14
  69. data/lib/async/matrix/bridge/discord/db/migrations/002_create_guilds.rb +0 -14
  70. data/lib/async/matrix/bridge/discord/db/migrations/003_create_portals.rb +0 -23
  71. data/lib/async/matrix/bridge/discord/db/migrations/004_create_puppets.rb +0 -19
  72. data/lib/async/matrix/bridge/discord/db/migrations/005_create_messages.rb +0 -20
  73. data/lib/async/matrix/bridge/discord/db/migrations/006_create_reactions.rb +0 -19
  74. data/lib/async/matrix/bridge/discord/db/migrations/007_create_files.rb +0 -18
  75. data/lib/async/matrix/bridge/discord/db/portal.rb +0 -150
  76. data/lib/async/matrix/bridge/discord/db/puppet.rb +0 -128
  77. data/lib/async/matrix/bridge/discord/db/reaction.rb +0 -165
  78. data/lib/async/matrix/bridge/discord/db/schema.rb +0 -18
  79. data/lib/async/matrix/bridge/discord/db/user.rb +0 -112
  80. data/lib/async/matrix/bridge/discord/db.rb +0 -138
@@ -9,346 +9,373 @@ require "json_schemer"
9
9
  require "pathname"
10
10
 
11
11
  module Async
12
- module Matrix
13
- module Schema
14
- # Loads and indexes Matrix event schemas from the official matrix-org/matrix-spec
15
- # YAML files bundled in data/matrix-spec/event-schemas/schema/.
16
- #
17
- # Schemas are loaded lazily on first access and cached for the lifetime of the
18
- # process. Each schema is a JSONSchemer::Schema instance that resolves relative
19
- # $ref paths (e.g. core-event-schema/room_event.yaml) via a file-based resolver.
20
- #
21
- # registry = Async::Matrix::Schema::Registry.instance
22
- # registry["m.room.message"] # => JSONSchemer::Schema
23
- # registry.variant("m.room.message", "m.text") # => JSONSchemer::Schema
24
- # registry.event_types # => ["m.accepted_terms", ...]
25
- #
26
- class Registry
27
- # Custom format validators for Matrix-specific format hints.
28
- MATRIX_FORMATS = {
29
- "mx-user-id" => ->(value, _schema) { value.is_a?(String) && value.match?(/\A@[^:]+:.+\z/) },
30
- "mx-room-id" => ->(value, _schema) { value.is_a?(String) && value.match?(/\A![^:]+:.+\z/) },
31
- "mx-event-id" => ->(value, _schema) { value.is_a?(String) && value.match?(/\A\$/) },
32
- "mx-room-alias" => ->(value, _schema) { value.is_a?(String) && value.match?(/\A#[^:]+:.+\z/) },
33
- "mx-server-name" => ->(value, _schema) { value.is_a?(String) && !value.empty? },
34
- "mx-unpadded-base64" => ->(value, _schema) { value.is_a?(String) && value.match?(/\A[A-Za-z0-9+\/]*\z/) },
35
- }.freeze
36
-
37
- GEM_ROOT = File.expand_path("../../../..", __dir__)
38
- SCHEMA_DIR = File.join(GEM_ROOT, "data", "matrix-spec", "event-schemas", "schema")
39
-
40
- @instance = nil
41
-
42
- class << self
43
- # Returns the singleton Registry instance, creating it on first access.
44
- def instance
45
- @instance ||= new
46
- end
47
-
48
- # Reset the singleton (useful for testing).
49
- def reset!
50
- @instance = nil
51
- end
52
- end
53
-
54
- def initialize
55
- @schemas = {}
56
- @variants = {}
57
- @loaded = false
58
- end
59
-
60
- # Look up a schema by Matrix event type (e.g. "m.room.message").
61
- # Returns a JSONSchemer::Schema or nil if no schema exists for that type.
62
- def [](event_type)
63
- load_schemas! unless @loaded
64
- @schemas[event_type]
65
- end
66
-
67
- # Look up a variant schema (e.g. variant("m.room.message", "m.text")).
68
- # Returns a JSONSchemer::Schema or nil.
69
- def variant(event_type, subtype)
70
- load_schemas! unless @loaded
71
- @variants[[event_type, subtype]]
72
- end
73
-
74
- # All known base event types (excludes variant subtypes).
75
- # @return [Array<String>] sorted event type strings
76
- def event_types
77
- load_schemas! unless @loaded
78
- @schemas.keys.sort
79
- end
80
-
81
- # All known variant keys as [event_type, subtype] pairs.
82
- # @return [Array<Array(String, String)>]
83
- def variant_types
84
- load_schemas! unless @loaded
85
- @variants.keys.sort
86
- end
87
-
88
- # Total number of schemas loaded (base + variants).
89
- def size
90
- load_schemas! unless @loaded
91
- @schemas.size + @variants.size
92
- end
93
-
94
- # Validate an event hash against its schema.
95
- # Returns an array of error hashes (empty if valid).
96
- # If no schema exists for the event type, returns empty (lenient).
97
- def validate(event_hash)
98
- event_type = event_hash["type"]
99
- return [] unless event_type
100
-
101
- base = self[event_type]
102
- return [] unless base
103
-
104
- errors = base.validate(event_hash).to_a
105
-
106
- # Also validate against variant if applicable
107
- variant_key = detect_variant_key(event_type, event_hash)
108
- if variant_key
109
- variant_schema = variant(event_type, variant_key)
110
- if variant_schema
111
- errors.concat(variant_schema.validate(event_hash).to_a)
112
- end
113
- end
114
-
115
- errors
116
- end
117
-
118
- # Boolean validation.
119
- def valid?(event_hash)
120
- validate(event_hash).empty?
121
- end
122
-
123
- # Content properties defined by the schema for a given event type.
124
- # Returns an array of property name strings, or empty array if unknown.
125
- def content_properties(event_type)
126
- schema = self[event_type]
127
- return [] unless schema
128
-
129
- extract_content_properties(schema.value)
130
- end
131
-
132
- private
133
-
134
- # Ref resolver that loads YAML/JSON files from disk.
135
- # json_schemer calls this with a URI for each $ref it encounters.
136
- def ref_resolver
137
- @ref_resolver ||= proc do |uri|
138
- path = uri.path
139
- if path && File.exist?(path)
140
- content = File.read(path)
141
- if path.end_with?(".yaml", ".yml")
142
- YAML.safe_load(content, permitted_classes: [Symbol])
143
- else
144
- JSON.parse(content)
145
- end
146
- else
147
- raise JSONSchemer::UnknownRef, uri.to_s
148
- end
149
- end
150
- end
151
-
152
- # Build a JSONSchemer::Schema from a parsed YAML hash, anchored at the
153
- # given file path so relative $ref paths resolve correctly.
154
- def build_schemer(parsed, file_path)
155
- uri = URI("file://#{File.expand_path(file_path)}")
156
- JSONSchemer.schema(
157
- parsed,
158
- base_uri: uri,
159
- ref_resolver: ref_resolver,
160
- insert_property_defaults: false,
161
- formats: MATRIX_FORMATS
162
- )
163
- end
164
-
165
- # Scan the schema directory and load all event schemas.
166
- def load_schemas!
167
- return if @loaded
168
-
169
- Dir.glob(File.join(SCHEMA_DIR, "*.yaml")).each do |path|
170
- load_schema_file(path)
171
- end
172
-
173
- # Also load JSON schema files (a few older schemas are JSON)
174
- Dir.glob(File.join(SCHEMA_DIR, "*.json")).each do |path|
175
- load_schema_file(path)
176
- end
177
-
178
- @loaded = true
179
- end
180
-
181
- def load_schema_file(path)
182
- filename = File.basename(path, File.extname(path))
183
- content = File.read(path)
184
- parsed = path.end_with?(".json") ? JSON.parse(content) : YAML.safe_load(content, permitted_classes: [Symbol])
185
-
186
- schemer = build_schemer(parsed, path)
187
-
188
- # Detect event type from schema: properties.type.enum[0]
189
- declared_type = parsed.dig("properties", "type", "enum")&.first
190
-
191
- if filename.include?("$")
192
- # Variant schema: "m.room.message$m.text" -> base="m.room.message", sub="m.text"
193
- parts = filename.split("$", 2)
194
- base_type = declared_type || parts[0]
195
- subtype = parts[1]
196
- @variants[[base_type, subtype]] = schemer
197
- elsif declared_type
198
- @schemas[declared_type] = schemer
199
- else
200
- # Schemas without a type enum (like core-event-schema/) are skipped
201
- # from the index -- they're only used as $ref targets.
202
- end
203
- rescue => e
204
- # Don't let a single broken schema prevent loading the rest
205
- warn "async-matrix: failed to load schema #{path}: #{e.message}"
206
- end
207
-
208
- # Detect the variant subtype key from an event hash.
209
- # For m.room.message, the variant is the msgtype.
210
- # For m.room.encrypted, the variant is the algorithm.
211
- # For m.key.verification.start, the variant is the method.
212
- def detect_variant_key(event_type, event_hash)
213
- content = event_hash["content"]
214
- return nil unless content.is_a?(Hash)
215
-
216
- case event_type
217
- when "m.room.message"
218
- content["msgtype"]
219
- when "m.room.encrypted"
220
- content["algorithm"]
221
- when "m.key.verification.start"
222
- content["method"]
223
- end
224
- end
225
-
226
- # Extract content property names from a schema's parsed YAML.
227
- def extract_content_properties(schema_hash)
228
- props = schema_hash.dig("properties", "content", "properties")
229
- return [] unless props.is_a?(Hash)
230
- props.keys
231
- end
232
- end
233
- end
234
- end
12
+ module Matrix
13
+ module Schema
14
+ # Loads and indexes Matrix event schemas from the official matrix-org/matrix-spec
15
+ # YAML files bundled in data/matrix-spec/event-schemas/schema/.
16
+ #
17
+ # Schemas are loaded lazily on first access and cached for the lifetime of the
18
+ # process. Each schema is a JSONSchemer::Schema instance that resolves relative
19
+ # $ref paths (e.g. core-event-schema/room_event.yaml) via a file-based resolver.
20
+ #
21
+ # registry = Async::Matrix::Schema::Registry.instance
22
+ # registry["m.room.message"] # => JSONSchemer::Schema
23
+ # registry.variant("m.room.message", "m.text") # => JSONSchemer::Schema
24
+ # registry.event_types # => ["m.accepted_terms", ...]
25
+ #
26
+ class Registry
27
+ # Custom format validators for Matrix-specific format hints.
28
+ MATRIX_FORMATS = {
29
+ "mx-user-id" => ->(value, _schema) { value.is_a?(String) && value.match?(/\A@[^:]+:.+\z/) },
30
+ "mx-room-id" => ->(value, _schema) { value.is_a?(String) && value.match?(/\A![^:]+:.+\z/) },
31
+ "mx-event-id" => ->(value, _schema) { value.is_a?(String) && value.match?(/\A\$/) },
32
+ "mx-room-alias" => ->(value, _schema) { value.is_a?(String) && value.match?(/\A#[^:]+:.+\z/) },
33
+ "mx-server-name" => ->(value, _schema) { value.is_a?(String) && !value.empty? },
34
+ "mx-unpadded-base64" => ->(value, _schema) { value.is_a?(String) && value.match?(/\A[A-Za-z0-9+\/]*\z/) },
35
+ }.freeze
36
+
37
+ GEM_ROOT = File.expand_path("../../../..", __dir__)
38
+ SCHEMA_DIR = File.join(
39
+ GEM_ROOT,
40
+ "data",
41
+ "matrix-spec",
42
+ "event-schemas",
43
+ "schema",
44
+ )
45
+
46
+ @instance = nil
47
+
48
+ class << self
49
+ # Returns the singleton Registry instance, creating it on first access.
50
+ def instance
51
+ @instance ||= new
52
+ end
53
+
54
+ # Reset the singleton (useful for testing).
55
+ def reset!
56
+ @instance = nil
57
+ end
58
+ end
59
+
60
+ def initialize
61
+ @schemas = {}
62
+ @variants = {}
63
+ @loaded = false
64
+ end
65
+
66
+ # Look up a schema by Matrix event type (e.g. "m.room.message").
67
+ # Returns a JSONSchemer::Schema or nil if no schema exists for that type.
68
+ def [](event_type)
69
+ unless @loaded
70
+ load_schemas!
71
+ end
72
+ @schemas[event_type]
73
+ end
74
+
75
+ # Look up a variant schema (e.g. variant("m.room.message", "m.text")).
76
+ # Returns a JSONSchemer::Schema or nil.
77
+ def variant(event_type, subtype)
78
+ unless @loaded
79
+ load_schemas!
80
+ end
81
+ @variants[[event_type, subtype]]
82
+ end
83
+
84
+ # All known base event types (excludes variant subtypes).
85
+ # @return [Array<String>] sorted event type strings
86
+ def event_types
87
+ unless @loaded
88
+ load_schemas!
89
+ end
90
+ @schemas.keys.sort
91
+ end
92
+
93
+ # All known variant keys as [event_type, subtype] pairs.
94
+ # @return [Array<Array(String, String)>]
95
+ def variant_types
96
+ unless @loaded
97
+ load_schemas!
98
+ end
99
+ @variants.keys.sort
100
+ end
101
+
102
+ # Total number of schemas loaded (base + variants).
103
+ def size
104
+ unless @loaded
105
+ load_schemas!
106
+ end
107
+ @schemas.size + @variants.size
108
+ end
109
+
110
+ # Validate an event hash against its schema.
111
+ # Returns an array of error hashes (empty if valid).
112
+ # If no schema exists for the event type, returns empty (lenient).
113
+ def validate(event_hash)
114
+ event_type = event_hash["type"]
115
+ if event_type
116
+ base = self[event_type]
117
+ if base
118
+ errors = base.validate(event_hash).to_a
119
+ variant_key = detect_variant_key(event_type, event_hash)
120
+ if variant_key
121
+ variant_schema = variant(event_type, variant_key)
122
+ if variant_schema
123
+ errors.concat(variant_schema.validate(event_hash).to_a)
124
+ end
125
+ end
126
+ errors
127
+ else
128
+ []
129
+ end
130
+ else
131
+ []
132
+ end
133
+ end
134
+
135
+ # Boolean validation.
136
+ def valid?(event_hash)
137
+ validate(event_hash).empty?
138
+ end
139
+
140
+ # Content properties defined by the schema for a given event type.
141
+ # Returns an array of property name strings, or empty array if unknown.
142
+ def content_properties(event_type)
143
+ schema = self[event_type]
144
+ if schema
145
+ extract_content_properties(schema.value)
146
+ else
147
+ []
148
+ end
149
+ end
150
+
151
+ private
152
+
153
+ # Ref resolver that loads YAML/JSON files from disk.
154
+ # json_schemer calls this with a URI for each $ref it encounters.
155
+ def ref_resolver
156
+ @ref_resolver ||= proc do |uri|
157
+ path = uri.path
158
+ if path && File.exist?(path)
159
+ content = File.read(path)
160
+ if path.end_with?(".yaml", ".yml")
161
+ YAML.safe_load(content, permitted_classes: [Symbol])
162
+ else
163
+ JSON.parse(content)
164
+ end
165
+ else
166
+ raise JSONSchemer::UnknownRef, uri.to_s
167
+ end
168
+ end
169
+ end
170
+
171
+ # Build a JSONSchemer::Schema from a parsed YAML hash, anchored at the
172
+ # given file path so relative $ref paths resolve correctly.
173
+ def build_schemer(parsed, file_path)
174
+ uri = URI("file://#{File.expand_path(file_path)}")
175
+ JSONSchemer.schema(
176
+ parsed,
177
+ base_uri: uri,
178
+ ref_resolver: ref_resolver,
179
+ insert_property_defaults: false,
180
+ formats: MATRIX_FORMATS,
181
+ )
182
+ end
183
+
184
+ # Scan the schema directory and load all event schemas.
185
+ def load_schemas!
186
+ if @loaded
187
+ nil
188
+ else
189
+ Dir.glob(File.join(SCHEMA_DIR, "*.yaml")).each do |path|
190
+ load_schema_file(path)
191
+ end
192
+ Dir.glob(File.join(SCHEMA_DIR, "*.json")).each do |path|
193
+ load_schema_file(path)
194
+ end
195
+ @loaded = true
196
+ end
197
+ end
198
+
199
+ def load_schema_file(path)
200
+ filename = File.basename(path, File.extname(path))
201
+ content = File.read(path)
202
+ if path.end_with?(".json")
203
+ parsed = JSON.parse(content)
204
+ else
205
+ parsed = YAML.safe_load(content, permitted_classes: [Symbol])
206
+ end
207
+
208
+ schemer = build_schemer(parsed, path)
209
+
210
+ # Detect event type from schema: properties.type.enum[0]
211
+ declared_type = parsed.dig("properties", "type", "enum")&.first
212
+
213
+ if filename.include?("$")
214
+ # Variant schema: "m.room.message$m.text" -> base="m.room.message", sub="m.text"
215
+ parts = filename.split("$", 2)
216
+ base_type = declared_type || parts[0]
217
+ subtype = parts[1]
218
+ @variants[[base_type, subtype]] = schemer
219
+ elsif declared_type
220
+ @schemas[declared_type] = schemer
221
+ else
222
+ # Schemas without a type enum (like core-event-schema/) are skipped
223
+ # from the index -- they're only used as $ref targets.
224
+ end
225
+ rescue => e
226
+ # Don't let a single broken schema prevent loading the rest
227
+ warn "async-matrix: failed to load schema #{path}: #{e.message}"
228
+ end
229
+
230
+ # Detect the variant subtype key from an event hash.
231
+ # For m.room.message, the variant is the msgtype.
232
+ # For m.room.encrypted, the variant is the algorithm.
233
+ # For m.key.verification.start, the variant is the method.
234
+ def detect_variant_key(event_type, event_hash)
235
+ content = event_hash["content"]
236
+ if content.is_a?(Hash)
237
+ case event_type
238
+ when "m.room.message"
239
+ content["msgtype"]
240
+ when "m.room.encrypted"
241
+ content["algorithm"]
242
+ when "m.key.verification.start"
243
+ content["method"]
244
+ end
245
+ else
246
+ nil
247
+ end
248
+ end
249
+
250
+ # Extract content property names from a schema's parsed YAML.
251
+ def extract_content_properties(schema_hash)
252
+ props = schema_hash.dig("properties", "content", "properties")
253
+ if props.is_a?(Hash)
254
+ props.keys
255
+ else
256
+ []
257
+ end
258
+ end
259
+ end
260
+ end
261
+ end
235
262
  end
236
263
 
237
264
  __END__
238
- describe "Async::Matrix::Schema::Registry" do
239
- it "loads schemas from disk" do
240
- Async::Matrix::Schema::Registry.instance.size.should.be > 0
241
- end
242
-
243
- it "has known event types" do
244
- types = Async::Matrix::Schema::Registry.instance.event_types
245
- types.should.include "m.room.message"
246
- types.should.include "m.room.member"
247
- types.should.include "m.room.create"
248
- types.should.include "m.reaction"
249
- end
250
-
251
- it "returns a JSONSchemer::Schema for a known type" do
252
- schema = Async::Matrix::Schema::Registry.instance["m.room.message"]
253
- schema.should.not.be.nil
254
- schema.should.be.kind_of JSONSchemer::Schema
255
- end
256
-
257
- it "returns nil for an unknown type" do
258
- Async::Matrix::Schema::Registry.instance["m.fake.event"].should.be.nil
259
- end
260
-
261
- it "has variant schemas" do
262
- Async::Matrix::Schema::Registry.instance.variant_types.should.not.be.empty
263
- end
264
-
265
- it "resolves variant schemas" do
266
- schema = Async::Matrix::Schema::Registry.instance.variant("m.room.message", "m.text")
267
- schema.should.not.be.nil
268
- schema.should.be.kind_of JSONSchemer::Schema
269
- end
270
-
271
- it "validates a correct m.room.message event" do
272
- event = {
273
- "type" => "m.room.message",
274
- "content" => {"msgtype" => "m.text", "body" => "hello"},
275
- "event_id" => "$abc123",
276
- "sender" => "@alice:example.org",
277
- "origin_server_ts" => 1234567890,
278
- "room_id" => "!room:example.org"
279
- }
280
- Async::Matrix::Schema::Registry.instance.valid?(event).should == true
281
- end
282
-
283
- it "rejects m.room.message missing body" do
284
- event = {
285
- "type" => "m.room.message",
286
- "content" => {"msgtype" => "m.text"},
287
- "event_id" => "$abc123",
288
- "sender" => "@alice:example.org",
289
- "origin_server_ts" => 1234567890,
290
- "room_id" => "!room:example.org"
291
- }
292
- Async::Matrix::Schema::Registry.instance.valid?(event).should == false
293
- end
294
-
295
- it "is lenient with unknown event types" do
296
- event = {
297
- "type" => "m.room.other",
298
- "content" => {"msgtype" => "m.text", "body" => "hi"},
299
- "event_id" => "$abc123",
300
- "sender" => "@alice:example.org",
301
- "origin_server_ts" => 1234567890,
302
- "room_id" => "!room:example.org"
303
- }
304
- Async::Matrix::Schema::Registry.instance.valid?(event).should == true
305
- end
306
-
307
- it "validates m.room.member with correct membership" do
308
- event = {
309
- "type" => "m.room.member",
310
- "content" => {"membership" => "join"},
311
- "state_key" => "@alice:example.org",
312
- "event_id" => "$abc123",
313
- "sender" => "@alice:example.org",
314
- "origin_server_ts" => 1234567890,
315
- "room_id" => "!room:example.org"
316
- }
317
- Async::Matrix::Schema::Registry.instance.valid?(event).should == true
318
- end
319
-
320
- it "rejects m.room.member with invalid membership" do
321
- event = {
322
- "type" => "m.room.member",
323
- "content" => {"membership" => "invalid_state"},
324
- "state_key" => "@alice:example.org",
325
- "event_id" => "$abc123",
326
- "sender" => "@alice:example.org",
327
- "origin_server_ts" => 1234567890,
328
- "room_id" => "!room:example.org"
329
- }
330
- Async::Matrix::Schema::Registry.instance.valid?(event).should == false
331
- end
332
-
333
- it "returns content properties for known types" do
334
- props = Async::Matrix::Schema::Registry.instance.content_properties("m.room.message")
335
- props.should.include "msgtype"
336
- props.should.include "body"
337
- end
338
-
339
- it "returns empty content properties for unknown types" do
340
- Async::Matrix::Schema::Registry.instance.content_properties("m.fake.type").should == []
341
- end
342
-
343
- it "performs variant validation for m.room.message with msgtype" do
344
- event = {
345
- "type" => "m.room.message",
346
- "content" => {"msgtype" => "m.text", "body" => "hello"},
347
- "event_id" => "$abc123",
348
- "sender" => "@alice:example.org",
349
- "origin_server_ts" => 1234567890,
350
- "room_id" => "!room:example.org"
351
- }
352
- Async::Matrix::Schema::Registry.instance.validate(event).should == []
353
- end
354
- end
265
+ describe "Async::Matrix::Schema::Registry" do
266
+ it "loads schemas from disk" do
267
+ Async::Matrix::Schema::Registry.instance.size.should.be > 0
268
+ end
269
+
270
+ it "has known event types" do
271
+ types = Async::Matrix::Schema::Registry.instance.event_types
272
+ types.should.include "m.room.message"
273
+ types.should.include "m.room.member"
274
+ types.should.include "m.room.create"
275
+ types.should.include "m.reaction"
276
+ end
277
+
278
+ it "returns a JSONSchemer::Schema for a known type" do
279
+ schema = Async::Matrix::Schema::Registry.instance["m.room.message"]
280
+ schema.should.not.be.nil
281
+ schema.should.be.kind_of JSONSchemer::Schema
282
+ end
283
+
284
+ it "returns nil for an unknown type" do
285
+ Async::Matrix::Schema::Registry.instance["m.fake.event"].should.be.nil
286
+ end
287
+
288
+ it "has variant schemas" do
289
+ Async::Matrix::Schema::Registry.instance.variant_types.should.not.be.empty
290
+ end
291
+
292
+ it "resolves variant schemas" do
293
+ schema = Async::Matrix::Schema::Registry.instance.variant("m.room.message", "m.text")
294
+ schema.should.not.be.nil
295
+ schema.should.be.kind_of JSONSchemer::Schema
296
+ end
297
+
298
+ it "validates a correct m.room.message event" do
299
+ event = {
300
+ "type" => "m.room.message",
301
+ "content" => {"msgtype" => "m.text", "body" => "hello"},
302
+ "event_id" => "$abc123",
303
+ "sender" => "@alice:example.org",
304
+ "origin_server_ts" => 1234567890,
305
+ "room_id" => "!room:example.org"
306
+ }
307
+ Async::Matrix::Schema::Registry.instance.valid?(event).should == true
308
+ end
309
+
310
+ it "rejects m.room.message missing body" do
311
+ event = {
312
+ "type" => "m.room.message",
313
+ "content" => {"msgtype" => "m.text"},
314
+ "event_id" => "$abc123",
315
+ "sender" => "@alice:example.org",
316
+ "origin_server_ts" => 1234567890,
317
+ "room_id" => "!room:example.org"
318
+ }
319
+ Async::Matrix::Schema::Registry.instance.valid?(event).should == false
320
+ end
321
+
322
+ it "is lenient with unknown event types" do
323
+ event = {
324
+ "type" => "m.room.other",
325
+ "content" => {"msgtype" => "m.text", "body" => "hi"},
326
+ "event_id" => "$abc123",
327
+ "sender" => "@alice:example.org",
328
+ "origin_server_ts" => 1234567890,
329
+ "room_id" => "!room:example.org"
330
+ }
331
+ Async::Matrix::Schema::Registry.instance.valid?(event).should == true
332
+ end
333
+
334
+ it "validates m.room.member with correct membership" do
335
+ event = {
336
+ "type" => "m.room.member",
337
+ "content" => {"membership" => "join"},
338
+ "state_key" => "@alice:example.org",
339
+ "event_id" => "$abc123",
340
+ "sender" => "@alice:example.org",
341
+ "origin_server_ts" => 1234567890,
342
+ "room_id" => "!room:example.org"
343
+ }
344
+ Async::Matrix::Schema::Registry.instance.valid?(event).should == true
345
+ end
346
+
347
+ it "rejects m.room.member with invalid membership" do
348
+ event = {
349
+ "type" => "m.room.member",
350
+ "content" => {"membership" => "invalid_state"},
351
+ "state_key" => "@alice:example.org",
352
+ "event_id" => "$abc123",
353
+ "sender" => "@alice:example.org",
354
+ "origin_server_ts" => 1234567890,
355
+ "room_id" => "!room:example.org"
356
+ }
357
+ Async::Matrix::Schema::Registry.instance.valid?(event).should == false
358
+ end
359
+
360
+ it "returns content properties for known types" do
361
+ props = Async::Matrix::Schema::Registry.instance.content_properties("m.room.message")
362
+ props.should.include "msgtype"
363
+ props.should.include "body"
364
+ end
365
+
366
+ it "returns empty content properties for unknown types" do
367
+ Async::Matrix::Schema::Registry.instance.content_properties("m.fake.type").should == []
368
+ end
369
+
370
+ it "performs variant validation for m.room.message with msgtype" do
371
+ event = {
372
+ "type" => "m.room.message",
373
+ "content" => {"msgtype" => "m.text", "body" => "hello"},
374
+ "event_id" => "$abc123",
375
+ "sender" => "@alice:example.org",
376
+ "origin_server_ts" => 1234567890,
377
+ "room_id" => "!room:example.org"
378
+ }
379
+ Async::Matrix::Schema::Registry.instance.validate(event).should == []
380
+ end
381
+ end