upkeep-rails 0.1.6

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.

Potentially problematic release.


This version of upkeep-rails might be problematic. Click here for more details.

Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +614 -0
  4. data/docs/architecture/ambient-inputs-roadmap.md +308 -0
  5. data/docs/architecture/herb-roadmap.md +324 -0
  6. data/docs/architecture/identity-and-sharing.md +306 -0
  7. data/docs/architecture/query-dependencies.md +230 -0
  8. data/docs/architecture/subscription-store-contract.md +66 -0
  9. data/docs/cost-model-roadmap.md +704 -0
  10. data/docs/guides/getting-started.md +462 -0
  11. data/docs/handoff-2026-05-15.md +230 -0
  12. data/docs/production_roadmap.md +372 -0
  13. data/docs/shared-warm-scale-roadmap.md +214 -0
  14. data/docs/single-subscriber-cold-roadmap.md +192 -0
  15. data/docs/stress-test-findings.md +310 -0
  16. data/docs/testing.md +143 -0
  17. data/lib/generators/upkeep/install/install_generator.rb +127 -0
  18. data/lib/generators/upkeep/install/templates/create_upkeep_subscriptions.rb.erb +49 -0
  19. data/lib/generators/upkeep/install/templates/subscription.js +99 -0
  20. data/lib/generators/upkeep/install/templates/upkeep.rb +63 -0
  21. data/lib/upkeep/active_record_query.rb +294 -0
  22. data/lib/upkeep/capture/request.rb +150 -0
  23. data/lib/upkeep/dag/subscription_shape.rb +244 -0
  24. data/lib/upkeep/dag.rb +370 -0
  25. data/lib/upkeep/delivery/action_cable_adapter.rb +43 -0
  26. data/lib/upkeep/delivery/async_dispatcher.rb +102 -0
  27. data/lib/upkeep/delivery/broadcast_transport.rb +89 -0
  28. data/lib/upkeep/delivery/transport.rb +194 -0
  29. data/lib/upkeep/delivery/turbo_streams.rb +302 -0
  30. data/lib/upkeep/delivery.rb +7 -0
  31. data/lib/upkeep/dependencies.rb +518 -0
  32. data/lib/upkeep/herb/developer_report.rb +135 -0
  33. data/lib/upkeep/herb/manifest_cache.rb +83 -0
  34. data/lib/upkeep/herb/manifest_diff.rb +183 -0
  35. data/lib/upkeep/herb/source_instrumenter.rb +149 -0
  36. data/lib/upkeep/herb/template_manifest.rb +514 -0
  37. data/lib/upkeep/invalidation/collection_append.rb +84 -0
  38. data/lib/upkeep/invalidation/collection_member_replace.rb +78 -0
  39. data/lib/upkeep/invalidation/collection_prepend.rb +84 -0
  40. data/lib/upkeep/invalidation/collection_remove.rb +57 -0
  41. data/lib/upkeep/invalidation/planner.rb +360 -0
  42. data/lib/upkeep/invalidation.rb +7 -0
  43. data/lib/upkeep/rails/action_view_capture.rb +821 -0
  44. data/lib/upkeep/rails/activation_token.rb +55 -0
  45. data/lib/upkeep/rails/cable/channel.rb +143 -0
  46. data/lib/upkeep/rails/cable/subscriber_identity.rb +341 -0
  47. data/lib/upkeep/rails/cable.rb +4 -0
  48. data/lib/upkeep/rails/client_subscription.rb +45 -0
  49. data/lib/upkeep/rails/configuration.rb +245 -0
  50. data/lib/upkeep/rails/controller_runtime.rb +137 -0
  51. data/lib/upkeep/rails/delivery_job.rb +29 -0
  52. data/lib/upkeep/rails/install.rb +28 -0
  53. data/lib/upkeep/rails/railtie.rb +50 -0
  54. data/lib/upkeep/rails/replay.rb +176 -0
  55. data/lib/upkeep/rails/testing.rb +97 -0
  56. data/lib/upkeep/rails.rb +349 -0
  57. data/lib/upkeep/replay.rb +408 -0
  58. data/lib/upkeep/runtime.rb +1100 -0
  59. data/lib/upkeep/shared_streams.rb +72 -0
  60. data/lib/upkeep/subscriptions/active_record_store.rb +383 -0
  61. data/lib/upkeep/subscriptions/active_record_subscription_persistence.rb +407 -0
  62. data/lib/upkeep/subscriptions/active_registry.rb +87 -0
  63. data/lib/upkeep/subscriptions/async_durable_writer.rb +131 -0
  64. data/lib/upkeep/subscriptions/json_snapshot.rb +98 -0
  65. data/lib/upkeep/subscriptions/layered_reverse_index.rb +129 -0
  66. data/lib/upkeep/subscriptions/persistent_reverse_index.rb +223 -0
  67. data/lib/upkeep/subscriptions/registrar.rb +36 -0
  68. data/lib/upkeep/subscriptions/reverse_index.rb +298 -0
  69. data/lib/upkeep/subscriptions/shape.rb +116 -0
  70. data/lib/upkeep/subscriptions/store.rb +171 -0
  71. data/lib/upkeep/subscriptions.rb +7 -0
  72. data/lib/upkeep/targeting.rb +135 -0
  73. data/lib/upkeep/version.rb +5 -0
  74. data/lib/upkeep-rails.rb +3 -0
  75. data/lib/upkeep.rb +14 -0
  76. data/upkeep-rails.gemspec +54 -0
  77. metadata +320 -0
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "digest"
4
+ require "nokogiri"
5
+
6
+ module Upkeep
7
+ module Targeting
8
+ Target = Data.define(:kind, :id, :reason)
9
+ Patch = Data.define(:target, :html)
10
+
11
+ class Selector
12
+ def select(recorder, changes)
13
+ graph = recorder.graph
14
+
15
+ frame_nodes =
16
+ graph.dependency_node_ids_matching(changes)
17
+ .flat_map { |dependency_id| graph.dependency_owner_ids(dependency_id) }
18
+ .flat_map { |owner_id| graph.nearest_frame_nodes_from(owner_id) }
19
+
20
+ uniq_targets(remove_contained_frames(graph, frame_nodes).filter_map { |frame| target_for_frame(frame) })
21
+ end
22
+
23
+ private
24
+
25
+ def remove_contained_frames(graph, frames)
26
+ frames.uniq(&:id).reject do |frame|
27
+ frames.any? { |candidate| candidate.id != frame.id && graph.contained_by?(frame.id, candidate.id) }
28
+ end
29
+ end
30
+
31
+ def target_for_frame(frame)
32
+ case frame.payload.fetch(:kind)
33
+ when "page"
34
+ Target.new("page", frame.id, "page frame dependency matched committed change")
35
+ when "render_site"
36
+ Target.new("render_site", frame.payload.fetch(:site_id), "render-site dependency matched committed change")
37
+ when "fragment"
38
+ Target.new("fragment", frame.id, "record attribute read matched committed attributes")
39
+ end
40
+ end
41
+
42
+ def uniq_targets(targets)
43
+ targets.uniq { |target| [target.kind, target.id] }
44
+ end
45
+ end
46
+
47
+ class Patcher
48
+ def initialize(html)
49
+ @fragment = Extraction.parse_html(html)
50
+ end
51
+
52
+ def apply(patches)
53
+ patches.each { |patch| apply_patch(patch) }
54
+ fragment.to_html
55
+ end
56
+
57
+ private
58
+
59
+ attr_reader :fragment
60
+
61
+ def apply_patch(patch)
62
+ node = node_for(patch.target)
63
+ raise "target not found in current DOM: #{patch.target.inspect}" unless node
64
+
65
+ replacement = replacement_for(patch)
66
+ node.replace(replacement)
67
+ end
68
+
69
+ def node_for(target)
70
+ Extraction.node_for(fragment, target)
71
+ end
72
+
73
+ def replacement_for(patch)
74
+ parsed = Extraction.parse_html(patch.html)
75
+ Extraction.node_for(parsed, patch.target) ||
76
+ parsed.children.find { |child| child.element? } ||
77
+ parsed.at_css("body > *")
78
+ end
79
+ end
80
+
81
+ module Extraction
82
+ module_function
83
+
84
+ def patches_from_full_rerender(full_html, targets)
85
+ targets.map { |target| Patch.new(target, extract_target_html(full_html, target)) }
86
+ end
87
+
88
+ def extract_target_html(html, target)
89
+ fragment = parse_html(html)
90
+ node = node_for(fragment, target)
91
+
92
+ raise "target not found in full rerender: #{target.inspect}" unless node
93
+
94
+ node.to_html
95
+ end
96
+
97
+ def node_for(fragment, target)
98
+ case target.kind
99
+ when "page"
100
+ fragment.at_css(%([data-upkeep-page-frame="#{css_escape(target.id)}"]))
101
+ when "fragment"
102
+ fragment.at_css(%([data-upkeep-frame="#{css_escape(target.id)}"]))
103
+ when "render_site"
104
+ fragment.at_css(%([data-upkeep-render-site="#{css_escape(target.id)}"]))
105
+ end
106
+ end
107
+
108
+ def normalize_html(html)
109
+ parse_html(html).to_html
110
+ end
111
+
112
+ def digest_html(html)
113
+ Digest::SHA256.hexdigest(normalize_html(html))
114
+ end
115
+
116
+ def frame_id_for(target)
117
+ target.kind == "render_site" ? "site:#{target.id}" : target.id
118
+ end
119
+
120
+ def css_escape(value)
121
+ value.to_s.gsub("\\", "\\\\\\").gsub('"', '\"')
122
+ end
123
+
124
+ def parse_html(html)
125
+ source = html.to_s
126
+
127
+ if source.match?(/\A\s*(?:<!doctype\b[^>]*>\s*)?<html[\s>]/i)
128
+ Nokogiri::HTML5.parse(source)
129
+ else
130
+ Nokogiri::HTML5.fragment(source)
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Upkeep
4
+ VERSION = "0.1.6"
5
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "upkeep"
data/lib/upkeep.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "upkeep/version"
4
+ require_relative "upkeep/dependencies"
5
+ require_relative "upkeep/dag"
6
+ require_relative "upkeep/replay"
7
+ require_relative "upkeep/active_record_query"
8
+ require_relative "upkeep/runtime"
9
+ require_relative "upkeep/targeting"
10
+ require_relative "upkeep/subscriptions"
11
+ require_relative "upkeep/shared_streams"
12
+ require_relative "upkeep/invalidation"
13
+ require_relative "upkeep/delivery"
14
+ require_relative "upkeep/rails"
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/upkeep/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "upkeep-rails"
7
+ spec.version = Upkeep::VERSION
8
+ spec.authors = [ "Felipe dos Anjos" ]
9
+ spec.email = [ "felipe.cavalheiro.anjos@gmail.com" ]
10
+ spec.license = "MIT"
11
+
12
+ spec.summary = "Dependency-tracked live updates for Rails views"
13
+ spec.description = "Upkeep records the data and identity dependencies used while Rails renders a view, then updates subscribed frames when matching application data changes."
14
+ spec.homepage = "https://github.com/fc-anjos/upkeep-rails"
15
+ spec.required_ruby_version = ">= 3.2.0"
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "#{spec.homepage}/tree/main"
18
+ spec.metadata["bug_tracker_uri"] = "#{spec.homepage}/issues"
19
+ spec.metadata["rubygems_mfa_required"] = "true"
20
+
21
+ internal_files = Dir[
22
+ "lib/upkeep/probes/**/*.rb",
23
+ "lib/upkeep/proofs/**/*.rb"
24
+ ] + %w[
25
+ lib/upkeep/domain.rb
26
+ lib/upkeep/herb/fallback_analyzer.rb
27
+ lib/upkeep/herb/performance_gate.rb
28
+ lib/upkeep/herb/runtime_alignment.rb
29
+ lib/upkeep/proof_support.rb
30
+ lib/upkeep/rendering.rb
31
+ lib/upkeep/templates.rb
32
+ ]
33
+
34
+ spec.files = (Dir[
35
+ "README.md",
36
+ "LICENSE.txt",
37
+ "upkeep-rails.gemspec",
38
+ "docs/**/*.md",
39
+ "lib/**/*.rb",
40
+ "lib/generators/**/templates/**/*"
41
+ ] - internal_files).sort
42
+ spec.require_paths = [ "lib" ]
43
+
44
+ spec.add_dependency "actionview", ">= 7.1", "< 9.0"
45
+ spec.add_dependency "actionpack", ">= 7.1", "< 9.0"
46
+ spec.add_dependency "actioncable", ">= 7.1", "< 9.0"
47
+ spec.add_dependency "activejob", ">= 7.1", "< 9.0"
48
+ spec.add_dependency "activerecord", ">= 7.1", "< 9.0"
49
+ spec.add_dependency "activesupport", ">= 7.1", "< 9.0"
50
+ spec.add_dependency "herb", ">= 0.10.1", "< 0.11"
51
+ spec.add_dependency "nokogiri", ">= 1.15", "< 2.0"
52
+ spec.add_dependency "railties", ">= 7.1", "< 9.0"
53
+ spec.add_dependency "turbo-rails", ">= 2.0", "< 3.0"
54
+ end
metadata ADDED
@@ -0,0 +1,320 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: upkeep-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.6
5
+ platform: ruby
6
+ authors:
7
+ - Felipe dos Anjos
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: actionview
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '7.1'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '9.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ version: '7.1'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '9.0'
32
+ - !ruby/object:Gem::Dependency
33
+ name: actionpack
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: '7.1'
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '9.0'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '7.1'
49
+ - - "<"
50
+ - !ruby/object:Gem::Version
51
+ version: '9.0'
52
+ - !ruby/object:Gem::Dependency
53
+ name: actioncable
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '7.1'
59
+ - - "<"
60
+ - !ruby/object:Gem::Version
61
+ version: '9.0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '7.1'
69
+ - - "<"
70
+ - !ruby/object:Gem::Version
71
+ version: '9.0'
72
+ - !ruby/object:Gem::Dependency
73
+ name: activejob
74
+ requirement: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '7.1'
79
+ - - "<"
80
+ - !ruby/object:Gem::Version
81
+ version: '9.0'
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '7.1'
89
+ - - "<"
90
+ - !ruby/object:Gem::Version
91
+ version: '9.0'
92
+ - !ruby/object:Gem::Dependency
93
+ name: activerecord
94
+ requirement: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - ">="
97
+ - !ruby/object:Gem::Version
98
+ version: '7.1'
99
+ - - "<"
100
+ - !ruby/object:Gem::Version
101
+ version: '9.0'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '7.1'
109
+ - - "<"
110
+ - !ruby/object:Gem::Version
111
+ version: '9.0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: activesupport
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '7.1'
119
+ - - "<"
120
+ - !ruby/object:Gem::Version
121
+ version: '9.0'
122
+ type: :runtime
123
+ prerelease: false
124
+ version_requirements: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '7.1'
129
+ - - "<"
130
+ - !ruby/object:Gem::Version
131
+ version: '9.0'
132
+ - !ruby/object:Gem::Dependency
133
+ name: herb
134
+ requirement: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 0.10.1
139
+ - - "<"
140
+ - !ruby/object:Gem::Version
141
+ version: '0.11'
142
+ type: :runtime
143
+ prerelease: false
144
+ version_requirements: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: 0.10.1
149
+ - - "<"
150
+ - !ruby/object:Gem::Version
151
+ version: '0.11'
152
+ - !ruby/object:Gem::Dependency
153
+ name: nokogiri
154
+ requirement: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '1.15'
159
+ - - "<"
160
+ - !ruby/object:Gem::Version
161
+ version: '2.0'
162
+ type: :runtime
163
+ prerelease: false
164
+ version_requirements: !ruby/object:Gem::Requirement
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ version: '1.15'
169
+ - - "<"
170
+ - !ruby/object:Gem::Version
171
+ version: '2.0'
172
+ - !ruby/object:Gem::Dependency
173
+ name: railties
174
+ requirement: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '7.1'
179
+ - - "<"
180
+ - !ruby/object:Gem::Version
181
+ version: '9.0'
182
+ type: :runtime
183
+ prerelease: false
184
+ version_requirements: !ruby/object:Gem::Requirement
185
+ requirements:
186
+ - - ">="
187
+ - !ruby/object:Gem::Version
188
+ version: '7.1'
189
+ - - "<"
190
+ - !ruby/object:Gem::Version
191
+ version: '9.0'
192
+ - !ruby/object:Gem::Dependency
193
+ name: turbo-rails
194
+ requirement: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: '2.0'
199
+ - - "<"
200
+ - !ruby/object:Gem::Version
201
+ version: '3.0'
202
+ type: :runtime
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '2.0'
209
+ - - "<"
210
+ - !ruby/object:Gem::Version
211
+ version: '3.0'
212
+ description: Upkeep records the data and identity dependencies used while Rails renders
213
+ a view, then updates subscribed frames when matching application data changes.
214
+ email:
215
+ - felipe.cavalheiro.anjos@gmail.com
216
+ executables: []
217
+ extensions: []
218
+ extra_rdoc_files: []
219
+ files:
220
+ - LICENSE.txt
221
+ - README.md
222
+ - docs/architecture/ambient-inputs-roadmap.md
223
+ - docs/architecture/herb-roadmap.md
224
+ - docs/architecture/identity-and-sharing.md
225
+ - docs/architecture/query-dependencies.md
226
+ - docs/architecture/subscription-store-contract.md
227
+ - docs/cost-model-roadmap.md
228
+ - docs/guides/getting-started.md
229
+ - docs/handoff-2026-05-15.md
230
+ - docs/production_roadmap.md
231
+ - docs/shared-warm-scale-roadmap.md
232
+ - docs/single-subscriber-cold-roadmap.md
233
+ - docs/stress-test-findings.md
234
+ - docs/testing.md
235
+ - lib/generators/upkeep/install/install_generator.rb
236
+ - lib/generators/upkeep/install/templates/create_upkeep_subscriptions.rb.erb
237
+ - lib/generators/upkeep/install/templates/subscription.js
238
+ - lib/generators/upkeep/install/templates/upkeep.rb
239
+ - lib/upkeep-rails.rb
240
+ - lib/upkeep.rb
241
+ - lib/upkeep/active_record_query.rb
242
+ - lib/upkeep/capture/request.rb
243
+ - lib/upkeep/dag.rb
244
+ - lib/upkeep/dag/subscription_shape.rb
245
+ - lib/upkeep/delivery.rb
246
+ - lib/upkeep/delivery/action_cable_adapter.rb
247
+ - lib/upkeep/delivery/async_dispatcher.rb
248
+ - lib/upkeep/delivery/broadcast_transport.rb
249
+ - lib/upkeep/delivery/transport.rb
250
+ - lib/upkeep/delivery/turbo_streams.rb
251
+ - lib/upkeep/dependencies.rb
252
+ - lib/upkeep/herb/developer_report.rb
253
+ - lib/upkeep/herb/manifest_cache.rb
254
+ - lib/upkeep/herb/manifest_diff.rb
255
+ - lib/upkeep/herb/source_instrumenter.rb
256
+ - lib/upkeep/herb/template_manifest.rb
257
+ - lib/upkeep/invalidation.rb
258
+ - lib/upkeep/invalidation/collection_append.rb
259
+ - lib/upkeep/invalidation/collection_member_replace.rb
260
+ - lib/upkeep/invalidation/collection_prepend.rb
261
+ - lib/upkeep/invalidation/collection_remove.rb
262
+ - lib/upkeep/invalidation/planner.rb
263
+ - lib/upkeep/rails.rb
264
+ - lib/upkeep/rails/action_view_capture.rb
265
+ - lib/upkeep/rails/activation_token.rb
266
+ - lib/upkeep/rails/cable.rb
267
+ - lib/upkeep/rails/cable/channel.rb
268
+ - lib/upkeep/rails/cable/subscriber_identity.rb
269
+ - lib/upkeep/rails/client_subscription.rb
270
+ - lib/upkeep/rails/configuration.rb
271
+ - lib/upkeep/rails/controller_runtime.rb
272
+ - lib/upkeep/rails/delivery_job.rb
273
+ - lib/upkeep/rails/install.rb
274
+ - lib/upkeep/rails/railtie.rb
275
+ - lib/upkeep/rails/replay.rb
276
+ - lib/upkeep/rails/testing.rb
277
+ - lib/upkeep/replay.rb
278
+ - lib/upkeep/runtime.rb
279
+ - lib/upkeep/shared_streams.rb
280
+ - lib/upkeep/subscriptions.rb
281
+ - lib/upkeep/subscriptions/active_record_store.rb
282
+ - lib/upkeep/subscriptions/active_record_subscription_persistence.rb
283
+ - lib/upkeep/subscriptions/active_registry.rb
284
+ - lib/upkeep/subscriptions/async_durable_writer.rb
285
+ - lib/upkeep/subscriptions/json_snapshot.rb
286
+ - lib/upkeep/subscriptions/layered_reverse_index.rb
287
+ - lib/upkeep/subscriptions/persistent_reverse_index.rb
288
+ - lib/upkeep/subscriptions/registrar.rb
289
+ - lib/upkeep/subscriptions/reverse_index.rb
290
+ - lib/upkeep/subscriptions/shape.rb
291
+ - lib/upkeep/subscriptions/store.rb
292
+ - lib/upkeep/targeting.rb
293
+ - lib/upkeep/version.rb
294
+ - upkeep-rails.gemspec
295
+ homepage: https://github.com/fc-anjos/upkeep-rails
296
+ licenses:
297
+ - MIT
298
+ metadata:
299
+ homepage_uri: https://github.com/fc-anjos/upkeep-rails
300
+ source_code_uri: https://github.com/fc-anjos/upkeep-rails/tree/main
301
+ bug_tracker_uri: https://github.com/fc-anjos/upkeep-rails/issues
302
+ rubygems_mfa_required: 'true'
303
+ rdoc_options: []
304
+ require_paths:
305
+ - lib
306
+ required_ruby_version: !ruby/object:Gem::Requirement
307
+ requirements:
308
+ - - ">="
309
+ - !ruby/object:Gem::Version
310
+ version: 3.2.0
311
+ required_rubygems_version: !ruby/object:Gem::Requirement
312
+ requirements:
313
+ - - ">="
314
+ - !ruby/object:Gem::Version
315
+ version: '0'
316
+ requirements: []
317
+ rubygems_version: 3.6.9
318
+ specification_version: 4
319
+ summary: Dependency-tracked live updates for Rails views
320
+ test_files: []