interfacets 0.1.0 → 0.9.99

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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +173 -1
  3. data/.tmp +5 -0
  4. data/LICENSE +21 -0
  5. data/Rakefile +9 -7
  6. data/lib/interfacets/client/actor.rb +20 -0
  7. data/lib/interfacets/client/assets.rb +210 -0
  8. data/lib/interfacets/client/bus.rb +73 -0
  9. data/lib/interfacets/client/channels/api.rb +102 -0
  10. data/lib/interfacets/client/channels/audio.rb +101 -0
  11. data/lib/interfacets/client/channels/base.rb +28 -0
  12. data/lib/interfacets/client/channels/page_visibility.rb +21 -0
  13. data/lib/interfacets/client/channels/react/builder.rb +203 -0
  14. data/lib/interfacets/client/channels/react/channel.rb +61 -0
  15. data/lib/interfacets/client/channels/react/dom.rb +91 -0
  16. data/lib/interfacets/client/channels/react/evaluator.rb +33 -0
  17. data/lib/interfacets/client/channels/speech_to_text.rb +100 -0
  18. data/lib/interfacets/client/channels/timer.rb +51 -0
  19. data/lib/interfacets/client/channels/url.rb +52 -0
  20. data/lib/interfacets/client/config.rb +22 -0
  21. data/lib/interfacets/client/delegator.rb +37 -0
  22. data/lib/interfacets/client/registry.rb +23 -0
  23. data/lib/interfacets/client/system.rb +88 -0
  24. data/lib/interfacets/client/utils/active_support_concern.rb +220 -0
  25. data/lib/interfacets/client/utils/mruby_patches.rb +81 -0
  26. data/lib/interfacets/client/utils/open_struct.rb +115 -0
  27. data/lib/interfacets/client/utils/securerandom.rb +69 -0
  28. data/lib/interfacets/client.rb +13 -0
  29. data/lib/interfacets/component_registry.rb +115 -0
  30. data/lib/interfacets/component_schema_parser.rb +84 -0
  31. data/lib/interfacets/mruby/build.dockerfile +66 -0
  32. data/lib/interfacets/mruby/build_config.rb +20 -0
  33. data/lib/interfacets/mruby/entrypoint.rb +23 -0
  34. data/lib/interfacets/mruby/init.c +66 -0
  35. data/lib/interfacets/server/api.rb +44 -0
  36. data/lib/interfacets/server/assets/facet.rb +63 -0
  37. data/lib/interfacets/server/assets.rb +216 -0
  38. data/lib/interfacets/server/basic_router.rb +79 -0
  39. data/lib/interfacets/server/bus.rb +34 -0
  40. data/lib/interfacets/server/config.rb +87 -0
  41. data/lib/interfacets/server/facets/deserializer.rb +25 -0
  42. data/lib/interfacets/server/facets/schema/serializer.rb +54 -0
  43. data/lib/interfacets/server/facets/serializer.rb +50 -0
  44. data/lib/interfacets/server/registry.rb +51 -0
  45. data/lib/interfacets/shared/basic_routable.rb +45 -0
  46. data/lib/interfacets/shared/entities/bus.rb +230 -0
  47. data/lib/interfacets/shared/entities/collection_proxy.rb +190 -0
  48. data/lib/interfacets/shared/entities/specs/handlers.rb +133 -0
  49. data/lib/interfacets/shared/entities/specs.rb +161 -0
  50. data/lib/interfacets/shared/entity.rb +102 -0
  51. data/lib/interfacets/shared/entity_dsl.rb +154 -0
  52. data/lib/interfacets/shared/facet.rb +200 -0
  53. data/lib/interfacets/shared/generated_store.rb +149 -0
  54. data/lib/interfacets/shared/utils.rb +54 -0
  55. data/lib/interfacets/shared/validations.rb +75 -0
  56. data/lib/interfacets/shared/view.rb +74 -0
  57. data/lib/interfacets/test/component_registry.rb +63 -0
  58. data/lib/interfacets/test/js/inline_bus.rb +100 -0
  59. data/lib/interfacets/test/js/nodo_bus.rb +98 -0
  60. data/lib/interfacets/test/js/receivers/api.rb +48 -0
  61. data/lib/interfacets/test/js/receivers/react/node/xml_parser.rb +75 -0
  62. data/lib/interfacets/test/js/receivers/react/node.rb +133 -0
  63. data/lib/interfacets/test/js/receivers/react.rb +32 -0
  64. data/lib/interfacets/test/js/receivers/timer.rb +77 -0
  65. data/lib/interfacets/test/js/receivers/url.rb +60 -0
  66. data/lib/interfacets/test/standard_elements.yml +173 -0
  67. data/lib/interfacets/test/ui_simulator.rb +75 -0
  68. data/lib/interfacets/test/validation_engine.rb +151 -0
  69. data/lib/interfacets/test.rb +13 -0
  70. data/lib/interfacets/version.rb +1 -1
  71. data/lib/interfacets.rb +29 -2
  72. metadata +114 -6
  73. data/README.md +0 -35
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5a9fc11b77c082c02a9bb6c8defdbf12b12fac9dff56d9009c723a26719e5ffa
4
- data.tar.gz: d0ae5775b216ff078d6f730cfe853aacce5bd0784c79929cf07350c78a0e5105
3
+ metadata.gz: 8e7e08a925c26ef4b7ee1e2aa2bbdcd716388b6f3aaa22f8d5bf9e7a51a76cee
4
+ data.tar.gz: 222f5f5f8129c913d19ce4f6d6331f820ad643a6198f35f63ce0b9df2743e059
5
5
  SHA512:
6
- metadata.gz: 7f818487b367acd4514130b7a0426509d6c8aea7c0620407ac95d49673683b5a0e33278064d5cff90cd02964f42a708d3532ebaa5fc9446e082ffa4b1faeb27e
7
- data.tar.gz: 3fd3d0db29f724a037eb84f450ed33af68b396346c9933d6492a8c67acb5f9acb372a5fd6b5275f30590394075c7c46b3566812940e432e031b914ba239a8bcb
6
+ metadata.gz: 68e278e17a2b033f8dc0ee6941f80a76d6ddb6bfeb0d7c79267ed24150d48b6d7e1ff54bda300cb0db5b4caa238632be5efe8b228fa018362482b7d8cea1264a
7
+ data.tar.gz: 3ca6b351b7089d7e9d99e513a282c937cea531a813a1ebfdfd35a514b2f34f95187f19c63ac57e1a5691c61d111f67f2dbae0b614c490c252a2f76b3dcc5006a
data/.rubocop.yml CHANGED
@@ -1,8 +1,180 @@
1
1
  AllCops:
2
- TargetRubyVersion: 3.0
2
+ NewCops: enable
3
+ Exclude: [ "bin/*" ]
4
+
5
+ Layout/EmptyLinesAroundAttributeAccessor:
6
+ Enabled: false
7
+
8
+ Layout/MultilineMethodCallBraceLayout:
9
+ Enabled: true
10
+ EnforcedStyle: new_line
11
+
12
+ Layout/MultilineMethodCallIndentation:
13
+ Enabled: true
14
+ EnforcedStyle: indented
15
+
16
+ Layout/MultilineMethodArgumentLineBreaks:
17
+ Enabled: true
18
+
19
+ Layout/MultilineMethodParameterLineBreaks:
20
+ Enabled: true
21
+
22
+ Layout/FirstMethodArgumentLineBreak:
23
+ Enabled: true
24
+
25
+ Layout/FirstMethodParameterLineBreak:
26
+ Enabled: true
27
+
28
+ Style/MethodCallWithArgsParentheses:
29
+ Enabled: true
30
+
31
+ Layout/ArgumentAlignment:
32
+ Enabled: true
33
+ EnforcedStyle: with_fixed_indentation
34
+
35
+ Lint/UnusedMethodArgument:
36
+ Enabled: false
37
+
38
+ Style/NumberedParameters:
39
+ Enabled: false
40
+
41
+ Style/OpenStructUse:
42
+ Enabled: false
43
+
44
+ Lint/EmptyBlock:
45
+ Enabled: false
46
+
47
+ Style/ExponentialNotation:
48
+ Enabled: false
49
+
50
+ Layout/MultilineAssignmentLayout:
51
+ Enabled: true
52
+ EnforcedStyle: new_line
53
+
54
+ Layout/ExtraSpacing:
55
+ Enabled: true
56
+ AllowForAlignment: false
57
+
58
+ Metrics/AbcSize:
59
+ Enabled: false
60
+
61
+ Metrics/BlockLength:
62
+ Enabled: false
63
+
64
+ Metrics/ClassLength:
65
+ Enabled: false
66
+
67
+ Metrics/CyclomaticComplexity:
68
+ Enabled: false
69
+
70
+ Metrics/MethodLength:
71
+ Enabled: false
72
+
73
+ Metrics/ModuleLength:
74
+ Enabled: false
75
+
76
+ Metrics/PerceivedComplexity:
77
+ Enabled: false
78
+
79
+ Naming/MethodParameterName:
80
+ Enabled: false
81
+
82
+ Naming/PredicateName:
83
+ Enabled: false
84
+
85
+ Naming/VariableNumber:
86
+ EnforcedStyle: snake_case
87
+
88
+ Security/Eval:
89
+ Enabled: false
90
+
91
+ Style/Alias:
92
+ Enabled: false
93
+
94
+ Style/BlockDelimiters:
95
+ Enabled: false
96
+ EnforcedStyle: semantic
97
+
98
+ Style/CaseLikeIf:
99
+ Enabled: false
100
+
101
+ Style/CombinableLoops:
102
+ Enabled: false
103
+
104
+ Style/Documentation:
105
+ Enabled: false
106
+
107
+ Style/EmptyLambdaParameter:
108
+ Enabled: false
109
+
110
+ Style/EvenOdd:
111
+ Enabled: false
112
+
113
+
114
+ Style/GuardClause:
115
+ Enabled: false
116
+
117
+ Style/IfUnlessModifier:
118
+ Enabled: false
119
+
120
+ Style/Lambda:
121
+ Enabled: false
122
+
123
+ Style/ModuleFunction:
124
+ Enabled: false
125
+
126
+ Style/MultilineBlockChain:
127
+ Enabled: false
128
+
129
+ Style/MultilineMemoization:
130
+ Enabled: true
131
+ EnforcedStyle: braces
132
+
133
+ Style/ParenthesesAroundCondition:
134
+ Enabled: true
135
+ AllowInMultilineConditions: true
136
+
137
+ Style/RaiseArgs:
138
+ Enabled: true
139
+ EnforcedStyle: compact
140
+
141
+ Style/RedundantParentheses:
142
+ Enabled: false
143
+
144
+ Style/RedundantSelf:
145
+ Enabled: false
3
146
 
4
147
  Style/StringLiterals:
148
+ Enabled: true
5
149
  EnforcedStyle: double_quotes
6
150
 
7
151
  Style/StringLiteralsInInterpolation:
152
+ Enabled: true
8
153
  EnforcedStyle: double_quotes
154
+
155
+ Style/SymbolArray:
156
+ Enabled: true
157
+ EnforcedStyle: brackets
158
+
159
+ Style/TrailingCommaInArguments:
160
+ Enabled: true
161
+ EnforcedStyleForMultiline: consistent_comma
162
+
163
+ Style/TrailingCommaInArrayLiteral:
164
+ Enabled: true
165
+ EnforcedStyleForMultiline: consistent_comma
166
+
167
+ Style/TrailingCommaInHashLiteral:
168
+ Enabled: true
169
+ EnforcedStyleForMultiline: consistent_comma
170
+
171
+ Style/WordArray:
172
+ Enabled: true
173
+ EnforcedStyle: brackets
174
+
175
+ Layout/LineLength:
176
+ Max: 100
177
+ AllowedPatterns: ['^(\s*#)']
178
+
179
+ Style/DocumentDynamicEvalDefinition:
180
+ Enabled: false
data/.tmp ADDED
@@ -0,0 +1,5 @@
1
+ import { Test } from
2
+
3
+ export const registry = {
4
+ Test,
5
+ };
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Pete Kinnecom
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/Rakefile CHANGED
@@ -3,10 +3,12 @@
3
3
  require "bundler/gem_tasks"
4
4
  require "minitest/test_task"
5
5
 
6
- Minitest::TestTask.create
7
-
8
- require "rubocop/rake_task"
9
-
10
- RuboCop::RakeTask.new
11
-
12
- task default: %i[test rubocop]
6
+ Minitest::TestTask.create do |t|
7
+ t.warning = false
8
+ t.test_globs = (
9
+ Rake::FileList["test/**/test_*.rb", "test/**/*_test.rb"]
10
+ .exclude("test/fixtures/**/*")
11
+ )
12
+ end
13
+
14
+ task default: :test
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Interfacets
4
+ module Client
5
+ class Actor
6
+ attr_reader :registry, :facet
7
+ def initialize(registry:, channels:)
8
+ @registry = registry
9
+ end
10
+
11
+ def build_facet(name)
12
+ @facet = registry.build(name)
13
+ end
14
+
15
+ def render
16
+ facet.render(channels)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,210 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Style/MissingRespondToMissing
4
+ original_verbose = $VERBOSE
5
+ $VERBOSE = nil
6
+
7
+ TOP_LEVEL_BINDING = self.binding
8
+ DEFAULT_LOG_LEVEL = ENV.fetch("DEFAULT_LOG_LEVEL", "debug").to_sym
9
+
10
+ class InterfacetsLogger
11
+ class << self
12
+ def main
13
+ @main ||= new(level: DEFAULT_LOG_LEVEL)
14
+ end
15
+ end
16
+
17
+ LEVELS = {
18
+ debug: 0,
19
+ info: 1,
20
+ warn: 2,
21
+ error: 3,
22
+ fatal: 4
23
+ }.freeze
24
+
25
+ attr_accessor :level
26
+ def initialize(level: :info)
27
+ @level = LEVELS[level] || LEVELS[:info]
28
+ end
29
+
30
+ # Meta-program the logging methods
31
+ LEVELS.each do |method_name, level_value|
32
+ define_method(method_name) do |message|
33
+ puts "#{method_name.to_s.upcase}: #{message}" if level_value >= @level
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ $VERBOSE = original_verbose
40
+
41
+ module Interfacets
42
+ module Client
43
+ module Assets
44
+ class << self
45
+ attr_reader :loader
46
+
47
+ def logger
48
+ $asset_logger ||= InterfacetsLogger.main
49
+ end
50
+
51
+ def bootstrap(assets)
52
+ @loader = Loader.new(assets)
53
+ Assets.logger.debug("bootstrapping")
54
+
55
+ assets
56
+ .fetch("scaffolding")
57
+ .reject { _1.match(/SecureRandom/) } #total hack, bake this into image
58
+ .join("\n")
59
+ .then { TOP_LEVEL_BINDING.eval(_1) }
60
+
61
+ Assets.logger.debug("done bootstrapping")
62
+
63
+ assets.fetch("fs_map").each_key do |path|
64
+ Assets.logger.debug("planned load: #{path}")
65
+ @loader.load_path(path)
66
+ end
67
+ end
68
+ end
69
+
70
+ class Loader
71
+ attr_reader :assets
72
+ def initialize(assets)
73
+ @assets = assets
74
+ @loaded_classes = {}
75
+ @loaded_paths = {}
76
+ end
77
+
78
+ def path_loaded?(path)
79
+ @loaded_paths.key?(path)
80
+ end
81
+
82
+ def load_path(path)
83
+ return if @loaded_paths.key?(path)
84
+
85
+ @loaded_paths[path] = true
86
+
87
+ Assets.logger.debug("loading: #{path}")
88
+
89
+ TOP_LEVEL_BINDING.eval(fs_map.fetch(path), path)
90
+ Assets.logger.debug("done loading: #{path}")
91
+ end
92
+
93
+ def loaded?(klass)
94
+ @loaded_classes.key?(klass)
95
+ end
96
+
97
+ def load(klass)
98
+ return if loaded?(klass)
99
+
100
+ @loaded_classes[klass] = true
101
+
102
+ return if klass.name.nil?
103
+
104
+ return unless const_map.key?(klass.name)
105
+
106
+ const_map
107
+ .fetch(klass.name)
108
+ .each {
109
+ Assets.logger.debug("klass caused load: #{_1}")
110
+ load_path(_1)
111
+ }
112
+ end
113
+
114
+ private
115
+
116
+ def scaffolding
117
+ @scaffolding ||= assets.fetch("scaffolding")
118
+ end
119
+
120
+ def fs_map
121
+ @fs_map ||= assets.fetch("fs_map")
122
+ end
123
+
124
+ def const_map
125
+ @const_map ||= assets.fetch("const_map")
126
+ end
127
+ end
128
+
129
+ module AutoloadHook
130
+ def extend_object(o)
131
+ if Assets.loader.loaded?(self)
132
+ super
133
+ else
134
+ Assets.loader.load(self)
135
+ send(:extend_object, o)
136
+ end
137
+ end
138
+
139
+ def inherited(mod)
140
+ if Assets.loader.loaded?(self)
141
+ super
142
+ else
143
+ Assets.loader.load(self)
144
+ send(:inherited, mod)
145
+ end
146
+ end
147
+
148
+ def append_features(mod)
149
+ if Assets.loader.loaded?(self)
150
+ super
151
+ else
152
+ Assets.loader.load(self)
153
+ send(:append_features, mod)
154
+ end
155
+ end
156
+
157
+ # def included(mod)
158
+ # Assets.logger.debug("included: #{self.name} into #{mod.name}")
159
+ # unless Assets.loader.loaded?(self)
160
+ # Assets.loader.load(self)
161
+ # send(:included, mod)
162
+ # else
163
+ # super
164
+ # end
165
+ # end
166
+
167
+ # def extended(mod)
168
+ # Assets.logger.debug("extended: #{mod.name}")
169
+ # unless Assets.loader.loaded?(self)
170
+ # Assets.logger.debug("loaded: #{self}, now extending")
171
+ # Assets.loader.load(self)
172
+ # send(:extended, mod)
173
+ # else
174
+ # Assets.logger.debug("already loaded: #{self}, not extending")
175
+ # super
176
+ # end
177
+ # end
178
+
179
+ # def prepended(mod)
180
+ # unless Assets.loader.loaded?(self)
181
+ # Assets.loader.load(self)
182
+ # send(:prepended, mod)
183
+ # else
184
+ # super
185
+ # end
186
+ # end
187
+
188
+ # don't think this is needed
189
+ # def const_missing(const_name)
190
+ # if Assets.loader.loaded?(self)
191
+ # super
192
+ # else
193
+ # Assets.loader.load(self)
194
+ # const_get(const_name)
195
+ # end
196
+ # end
197
+
198
+ def method_missing(meth, *a, **p, &)
199
+ if Assets.loader.loaded?(self)
200
+ super
201
+ else
202
+ Assets.loader.load(self)
203
+ send(meth, *a, **p, &)
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
210
+ # rubocop:enable Style/MissingRespondToMissing
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This pipes messages through channels. This allows channel authors to intercept
4
+ # and incoming and outgoing messages and dropping/ignoring/updating their own state
5
+
6
+ module Interfacets
7
+ module Client
8
+ class Bus
9
+ attr_reader(
10
+ :id,
11
+ :channels,
12
+ :channel_index,
13
+ :registry,
14
+ :entity,
15
+ :root_url,
16
+ )
17
+
18
+ def initialize(
19
+ id:,
20
+ channels:,
21
+ root_url:
22
+ )
23
+ @id = id
24
+ @channels = channels
25
+ @registry = Registry.new
26
+ @channel_index = channels.map { [_1.id, _1] }.to_h
27
+ @root_url = root_url
28
+ end
29
+
30
+ def url_for(path)
31
+ [
32
+ root_url,
33
+ path,
34
+ ]
35
+ .map { _1.sub(%r{/$}, "").sub(%r{^/}, "") }
36
+ .join("/")
37
+ end
38
+
39
+ def channel(name)
40
+ channel_index.fetch(name.to_s)
41
+ end
42
+
43
+ def handle(event)
44
+ channel_id = event.dig("destination", "channel")
45
+ raise("unknown event: #{event.inspect}") unless channel_id
46
+ channel = channel_index.fetch(channel_id)
47
+
48
+ channel.handle(
49
+ entity: @entity,
50
+ event: event.fetch("payload"),
51
+ build_entity: ->(name, id) {
52
+ @entity = registry.build(name, id)
53
+ channel_index.values.each { _1.prepare(@entity) }
54
+ @entity
55
+ }
56
+ )
57
+
58
+ channel_index.values.each { _1.prepare(entity) }
59
+
60
+ entity.class.view.new.render(entity:, channels: channel_index)
61
+
62
+ {
63
+ type: "interfacets:bus:render",
64
+ id: id,
65
+ payload: (
66
+ channel_index
67
+ .map { |name, chann| { id: name, payload: chann.result } }
68
+ )
69
+ }
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Interfacets
4
+ module Client
5
+ module Channels
6
+ class Api
7
+ include Channels::Base
8
+
9
+ class Builder
10
+ attr_accessor :request, :entity
11
+
12
+ def render(path)
13
+ raise("only one submission per action") if request
14
+
15
+ System.logger.debug("Getting #{path}")
16
+
17
+ request_id = SecureRandom.uuid
18
+
19
+ self.request = {
20
+ url: Client::System.current_bus.url_for(path),
21
+ method: "get",
22
+ }
23
+ end
24
+
25
+ def submit(meth, nesting: )
26
+ raise("only one submission per action") if request
27
+
28
+ System.logger.debug("submitting #{meth}")
29
+
30
+ request_id = SecureRandom.uuid
31
+
32
+ self.request = {
33
+ url: (
34
+ if entity.respond_to?(:api_path)
35
+ Client::System.current_bus.url_for(entity.api_path)
36
+ end
37
+ ),
38
+ method: "put",
39
+ body: {
40
+ event: {
41
+ id: request_id,
42
+ type: "interfacets:api:submit",
43
+ payload: (
44
+ Shared::Entities::Bus
45
+ .new(entity:)
46
+ .serialize(
47
+ to: "server" ,
48
+ action: meth,
49
+ nesting:
50
+ )
51
+ )
52
+ },
53
+ },
54
+ }
55
+ end
56
+ end
57
+
58
+ type("interfacets:api")
59
+
60
+ def prepare(entity)
61
+ # must persist builder here
62
+ # probably all channels need to persist their
63
+ # builder. Because the bus calls "handle" before
64
+ # the "prepare" call. Perhaps these should be
65
+ # reversed?
66
+ @builder ||= Builder.new
67
+ @builder.entity = entity
68
+ end
69
+
70
+ def builder(stream = "default")
71
+ @builder
72
+ end
73
+
74
+ def result
75
+ {
76
+ streams: {
77
+ default: @builder.request,
78
+ },
79
+ }.tap { @builder.request = nil }
80
+ end
81
+
82
+ def handle(event:, entity:, build_entity:)
83
+ facet_name = event.fetch("facet")
84
+ id = event.dig(
85
+ "payload",
86
+ "payload",
87
+ "attributes",
88
+ "internal_entity_id"
89
+ )
90
+
91
+ entity = build_entity.(facet_name, id)
92
+
93
+ Shared::Entities::Bus
94
+ .new(entity:)
95
+ .handle(
96
+ event: event.fetch("payload")
97
+ )
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end