message_bus 4.5.1 → 4.6.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: bfc460d9e05c0273fa4136ea6f7756ef7fc262cf9202103f4f24a23c25d77276
4
- data.tar.gz: 171e848f636251b6b585de15c2fe869c8d2687380bc2b0965fdc33d8661a0cec
3
+ metadata.gz: ac878307b45991461b9a20bf6a4f31935c164aa6abce9ba8d931ae291869dbb9
4
+ data.tar.gz: 201fd5f776e4fb437eb3f2be49961d9469f81745b60b6f84dcccb332212cdd5d
5
5
  SHA512:
6
- metadata.gz: f9a1d9635fe6b2e9f51a87ce3c9a7e6bc0e1218a349af8e1a8ed62c77f37ebb8a6f89f630e83f6459f41804d442f644366ec44d3bad76e42d09e572510f23614
7
- data.tar.gz: e05072c606a9114d6b817c8c6eead0ba2122f291fd251b5e644013246dcc98394ae3153c2e5530bc499c00a3713164d7d432cfee8f4407867b61c2040fb985a0
6
+ metadata.gz: f54fb643cb48006c33585e2af967b9e0ae9bb69c5c034b3e454cbe82b9330e1fbbfdb3d58bf60cf6056522e67a59c2b519f18dd851d0fe3fe62e4d96dfe559e5
7
+ data.tar.gz: 9c358176d7f5441931f1d0505b2c9e17c330806af06fa310393ba321e9db0b0041c433cc12c79e5247d85f85983ffc592b45ee8be4cd939297e7e8411360e6ae
@@ -38,10 +38,11 @@ jobs:
38
38
 
39
39
  test:
40
40
  runs-on: ubuntu-latest
41
- name: Ruby ${{ matrix.ruby }} (${{ matrix.redis }})
41
+ name: Ruby ${{ matrix.ruby }} (${{ matrix.redis }}, ${{ matrix.rack }})
42
42
  timeout-minutes: 10
43
43
 
44
44
  env:
45
+ BUNDLE_GEMFILE: gemfiles/${{ matrix.rack }}.gemfile
45
46
  PGHOST: localhost
46
47
  PGPASSWORD: postgres
47
48
  PGUSER: postgres
@@ -50,7 +51,8 @@ jobs:
50
51
  fail-fast: false
51
52
  matrix:
52
53
  ruby: ["3.2", "3.3", "3.4"]
53
- redis: ["redis:5", "redis:6", "valkey/valkey"]
54
+ rack: ["rack2", "rack3"]
55
+ redis: ["redis:7.4", "valkey/valkey"]
54
56
 
55
57
  services:
56
58
  postgres:
data/.gitignore CHANGED
@@ -4,6 +4,7 @@
4
4
  .config
5
5
  .yardoc
6
6
  Gemfile.lock
7
+ gemfiles/*.gemfile.lock
7
8
  InstalledFiles
8
9
  _yardoc
9
10
  coverage
data/CHANGELOG CHANGED
@@ -1,3 +1,22 @@
1
+ 03-08-2026
2
+
3
+ - Version 4.6.0
4
+
5
+ - DEV: Export the JavaScript client as a CommonJS/ES module so it can be imported directly by bundlers and ESM projects, while still assigning the `MessageBus` global for existing consumers
6
+
7
+ 13-02-2026
8
+
9
+ - Version 4.5.2
10
+
11
+ - FIX: Use consistent casing for headers
12
+ - DEV: Test against both Rack 2 and Rack 3 in CI
13
+
14
+ 10-02-2026
15
+
16
+ - Version 4.5.1
17
+
18
+ - DEV: Allow 2.x rack dependency
19
+
1
20
  10-02-2026
2
21
 
3
22
  - Version 4.5.0
@@ -1,4 +1,4 @@
1
- /*global define, jQuery*/
1
+ /*global define, jQuery, module*/
2
2
 
3
3
  (function (root, factory) {
4
4
  if (typeof define === "function" && define.amd) {
@@ -9,6 +9,11 @@
9
9
  // a global even when an AMD loader is in use.
10
10
  return (root.MessageBus = factory());
11
11
  });
12
+ } else if (typeof module === "object" && module.exports) {
13
+ module.exports = factory();
14
+ if (typeof self !== "undefined") {
15
+ self.MessageBus = module.exports;
16
+ }
12
17
  } else {
13
18
  // Browser globals
14
19
  root.MessageBus = factory();
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ eval_gemfile "../Gemfile"
4
+
5
+ gem "rack", "~> 2.0"
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ eval_gemfile "../Gemfile"
4
+
5
+ gem "rack", "~> 3.0"
@@ -144,9 +144,7 @@ class MessageBus::Client
144
144
  end
145
145
 
146
146
  if has_groups
147
- group_allowed = (
148
- msg.group_ids - (self.group_ids || [])
149
- ).length < msg.group_ids.length
147
+ group_allowed = msg.group_ids.intersect?(self.group_ids || [])
150
148
  end
151
149
 
152
150
  has_permission = client_allowed && (user_allowed || group_allowed || (!has_users && !has_groups))
@@ -228,18 +226,18 @@ class MessageBus::Client
228
226
  NEWLINE = "\r\n".freeze
229
227
  COLON_SPACE = ": ".freeze
230
228
  HTTP_11 = "HTTP/1.1 200 OK\r\n".freeze
231
- CONTENT_LENGTH = "Content-Length: ".freeze
232
- CONNECTION_CLOSE = "Connection: close\r\n".freeze
233
- CHUNKED_ENCODING = "Transfer-Encoding: chunked\r\n".freeze
234
- NO_SNIFF = "X-Content-Type-Options: nosniff\r\n".freeze
229
+ CONTENT_LENGTH = "content-length: ".freeze
230
+ CONNECTION_CLOSE = "connection: close\r\n".freeze
231
+ CHUNKED_ENCODING = "transfer-encoding: chunked\r\n".freeze
232
+ NO_SNIFF = "x-content-type-options: nosniff\r\n".freeze
235
233
 
236
- TYPE_TEXT = "Content-Type: text/plain; charset=utf-8\r\n".freeze
237
- TYPE_JSON = "Content-Type: application/json; charset=utf-8\r\n".freeze
234
+ TYPE_TEXT = "content-type: text/plain; charset=utf-8\r\n".freeze
235
+ TYPE_JSON = "content-type: application/json; charset=utf-8\r\n".freeze
238
236
 
239
237
  def write_headers
240
238
  @io.write(HTTP_11)
241
239
  @headers.each do |k, v|
242
- next if k == "Content-Type"
240
+ next if k == "content-type"
243
241
 
244
242
  @io.write(k)
245
243
  @io.write(COLON_SPACE)
@@ -1,8 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Represents a published message and its encoding for persistence.
4
- class MessageBus::Message < Struct.new(:global_id, :message_id, :channel, :data)
5
- attr_accessor :site_id, :user_ids, :group_ids, :client_ids
4
+ class MessageBus::Message
5
+ attr_accessor :global_id, :message_id, :channel, :data,
6
+ :site_id, :user_ids, :group_ids, :client_ids
7
+
8
+ def initialize(global_id, message_id, channel, data)
9
+ @global_id = global_id
10
+ @message_id = message_id
11
+ @channel = channel
12
+ @data = data
13
+ end
6
14
 
7
15
  def self.decode(encoded)
8
16
  s1 = encoded.index("|")
@@ -15,7 +23,7 @@ class MessageBus::Message < Struct.new(:global_id, :message_id, :channel, :data)
15
23
  channel.gsub!("$$123$$", "|")
16
24
  data = encoded[(s3 + 1), encoded.size]
17
25
 
18
- MessageBus::Message.new(global_id, message_id, channel, data)
26
+ new(global_id, message_id, channel, data)
19
27
  end
20
28
 
21
29
  # only tricky thing to encode is pipes in a channel name ... do a straight replace
@@ -26,4 +34,12 @@ class MessageBus::Message < Struct.new(:global_id, :message_id, :channel, :data)
26
34
  def encode_without_ids
27
35
  "#{channel.gsub("|", "$$123$$")}|#{data}"
28
36
  end
37
+
38
+ def ==(other)
39
+ other.is_a?(self.class) &&
40
+ self.global_id == other.global_id &&
41
+ self.message_id == other.message_id &&
42
+ self.channel == other.channel &&
43
+ self.data == other.data
44
+ end
29
45
  end
@@ -75,7 +75,7 @@ class MessageBus::Rack::Middleware
75
75
  if @bus.allow_broadcast? && env['PATH_INFO'] == @broadcast_route
76
76
  parsed = Rack::Request.new(env)
77
77
  @bus.publish parsed["channel"], parsed["data"]
78
- return [200, { "Content-Type" => "text/html" }, ["sent"]]
78
+ return [200, { "content-type" => "text/html" }, ["sent"]]
79
79
  end
80
80
 
81
81
  client_id = env['PATH_INFO'][@base_route_length..-1].split("/")[0]
@@ -169,9 +169,9 @@ class MessageBus::Rack::Middleware
169
169
  end
170
170
 
171
171
  if allow_chunked
172
- response.headers["X-Content-Type-Options"] = "nosniff"
173
- response.headers["Transfer-Encoding"] = "chunked"
174
- response.headers["Content-Type"] = "text/plain; charset=utf-8"
172
+ response.headers["x-content-type-options"] = "nosniff"
173
+ response.headers["transfer-encoding"] = "chunked"
174
+ response.headers["content-type"] = "text/plain; charset=utf-8"
175
175
  end
176
176
 
177
177
  response.status = 200
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MessageBus
4
- VERSION = "4.5.1"
4
+ VERSION = "4.6.0"
5
5
  end
data/message_bus.gemspec CHANGED
@@ -14,9 +14,10 @@ Gem::Specification.new do |gem|
14
14
  gem.name = "message_bus"
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = MessageBus::VERSION
17
- gem.required_ruby_version = ">= 2.6.0"
17
+ gem.required_ruby_version = ">= 3.2.0"
18
18
 
19
19
  gem.add_runtime_dependency 'rack', '> 2', '< 4'
20
+ gem.add_runtime_dependency 'logger'
20
21
 
21
22
  # Optional runtime dependencies
22
23
  gem.add_development_dependency 'redis'
@@ -37,7 +38,5 @@ Gem::Specification.new do |gem|
37
38
  gem.add_development_dependency 'oj'
38
39
  gem.add_development_dependency 'yard'
39
40
 
40
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0')
41
- gem.add_development_dependency 'rubocop-discourse', '3.8.1'
42
- end
41
+ gem.add_development_dependency 'rubocop-discourse', '3.8.1'
43
42
  end
data/package.json CHANGED
@@ -10,8 +10,6 @@
10
10
  "files": [
11
11
  "assets/message-bus.js"
12
12
  ],
13
- "jsnext:main": "assets/message-bus.js",
14
- "module": "assets/message-bus.js",
15
13
  "repository": "https://github.com/discourse/message_bus",
16
14
  "author": "Sam Saffron, Robin Ward",
17
15
  "license": "MIT",
@@ -32,6 +32,8 @@ describe MessageBus::Client do
32
32
  break if line == ""
33
33
 
34
34
  name, val = line.split(": ")
35
+ name = name.downcase
36
+ raise "duplicate header: #{name}" if headers.key?(name)
35
37
  headers[name] = val
36
38
  end
37
39
 
@@ -67,7 +69,7 @@ describe MessageBus::Client do
67
69
 
68
70
  status, headers, chunks = http_parse(lines)
69
71
 
70
- headers["Content-Type"].must_equal "text/plain; charset=utf-8"
72
+ headers["content-type"].must_equal "text/plain; charset=utf-8"
71
73
  status.must_equal "200"
72
74
  chunks.length.must_equal 2
73
75
 
@@ -21,7 +21,7 @@ describe MessageBus::Rack::Middleware do
21
21
  use FakeAsyncMiddleware, message_bus: bus
22
22
  use e_m if e_m
23
23
  use MessageBus::Rack::Middleware, message_bus: bus
24
- run lambda { |_env| [500, { 'Content-Type' => 'text/html' }, 'should not be called'] }
24
+ run lambda { |_env| [500, { 'content-type' => 'text/html' }, 'should not be called'] }
25
25
  }
26
26
 
27
27
  @async_middleware = builder.to_app
@@ -1,4 +1,4 @@
1
- /*global define, jQuery*/
1
+ /*global define, jQuery, module*/
2
2
 
3
3
  (function (root, factory) {
4
4
  if (typeof define === "function" && define.amd) {
@@ -9,6 +9,11 @@
9
9
  // a global even when an AMD loader is in use.
10
10
  return (root.MessageBus = factory());
11
11
  });
12
+ } else if (typeof module === "object" && module.exports) {
13
+ module.exports = factory();
14
+ if (typeof self !== "undefined") {
15
+ self.MessageBus = module.exports;
16
+ }
12
17
  } else {
13
18
  // Browser globals
14
19
  root.MessageBus = factory();
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: message_bus
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.5.1
4
+ version: 4.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Saffron
@@ -29,6 +29,20 @@ dependencies:
29
29
  - - "<"
30
30
  - !ruby/object:Gem::Version
31
31
  version: '4'
32
+ - !ruby/object:Gem::Dependency
33
+ name: logger
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
32
46
  - !ruby/object:Gem::Dependency
33
47
  name: redis
34
48
  requirement: !ruby/object:Gem::Requirement
@@ -308,6 +322,8 @@ files:
308
322
  - examples/chat/docker_container/update_chat
309
323
  - examples/minimal/Gemfile
310
324
  - examples/minimal/config.ru
325
+ - gemfiles/rack2.gemfile
326
+ - gemfiles/rack3.gemfile
311
327
  - lib/message_bus.rb
312
328
  - lib/message_bus/backends.rb
313
329
  - lib/message_bus/backends/base.rb
@@ -366,7 +382,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
366
382
  requirements:
367
383
  - - ">="
368
384
  - !ruby/object:Gem::Version
369
- version: 2.6.0
385
+ version: 3.2.0
370
386
  required_rubygems_version: !ruby/object:Gem::Requirement
371
387
  requirements:
372
388
  - - ">="