reactor_sdk 0.1.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.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +19 -0
  3. data/LICENSE.txt +21 -0
  4. data/README.md +281 -0
  5. data/lib/reactor_sdk/authentication.rb +137 -0
  6. data/lib/reactor_sdk/client.rb +186 -0
  7. data/lib/reactor_sdk/configuration.rb +102 -0
  8. data/lib/reactor_sdk/connection.rb +342 -0
  9. data/lib/reactor_sdk/endpoints/app_configurations.rb +42 -0
  10. data/lib/reactor_sdk/endpoints/audit_events.rb +64 -0
  11. data/lib/reactor_sdk/endpoints/base_endpoint.rb +207 -0
  12. data/lib/reactor_sdk/endpoints/builds.rb +62 -0
  13. data/lib/reactor_sdk/endpoints/callbacks.rb +38 -0
  14. data/lib/reactor_sdk/endpoints/companies.rb +42 -0
  15. data/lib/reactor_sdk/endpoints/data_elements.rb +251 -0
  16. data/lib/reactor_sdk/endpoints/environments.rb +174 -0
  17. data/lib/reactor_sdk/endpoints/extension_package_usage_authorizations.rb +51 -0
  18. data/lib/reactor_sdk/endpoints/extension_packages.rb +63 -0
  19. data/lib/reactor_sdk/endpoints/extensions.rb +181 -0
  20. data/lib/reactor_sdk/endpoints/hosts.rb +101 -0
  21. data/lib/reactor_sdk/endpoints/libraries.rb +872 -0
  22. data/lib/reactor_sdk/endpoints/notes.rb +11 -0
  23. data/lib/reactor_sdk/endpoints/profiles.rb +14 -0
  24. data/lib/reactor_sdk/endpoints/properties.rb +123 -0
  25. data/lib/reactor_sdk/endpoints/revisions.rb +102 -0
  26. data/lib/reactor_sdk/endpoints/rule_components.rb +218 -0
  27. data/lib/reactor_sdk/endpoints/rules.rb +240 -0
  28. data/lib/reactor_sdk/endpoints/search.rb +23 -0
  29. data/lib/reactor_sdk/endpoints/secrets.rb +76 -0
  30. data/lib/reactor_sdk/error.rb +115 -0
  31. data/lib/reactor_sdk/library_comparison_builder.rb +74 -0
  32. data/lib/reactor_sdk/library_snapshot_builder.rb +66 -0
  33. data/lib/reactor_sdk/paginator.rb +92 -0
  34. data/lib/reactor_sdk/rate_limiter.rb +96 -0
  35. data/lib/reactor_sdk/reference_extractor.rb +34 -0
  36. data/lib/reactor_sdk/resource_metadata.rb +73 -0
  37. data/lib/reactor_sdk/resource_normalizer.rb +90 -0
  38. data/lib/reactor_sdk/resources/app_configuration.rb +20 -0
  39. data/lib/reactor_sdk/resources/audit_event.rb +45 -0
  40. data/lib/reactor_sdk/resources/base_resource.rb +181 -0
  41. data/lib/reactor_sdk/resources/build.rb +64 -0
  42. data/lib/reactor_sdk/resources/callback.rb +16 -0
  43. data/lib/reactor_sdk/resources/company.rb +38 -0
  44. data/lib/reactor_sdk/resources/comprehensive_data_element.rb +28 -0
  45. data/lib/reactor_sdk/resources/comprehensive_extension.rb +30 -0
  46. data/lib/reactor_sdk/resources/comprehensive_resource.rb +31 -0
  47. data/lib/reactor_sdk/resources/comprehensive_rule.rb +26 -0
  48. data/lib/reactor_sdk/resources/comprehensive_upstream_chain.rb +50 -0
  49. data/lib/reactor_sdk/resources/comprehensive_upstream_chain_entry.rb +34 -0
  50. data/lib/reactor_sdk/resources/data_element.rb +108 -0
  51. data/lib/reactor_sdk/resources/environment.rb +45 -0
  52. data/lib/reactor_sdk/resources/extension.rb +66 -0
  53. data/lib/reactor_sdk/resources/extension_package.rb +49 -0
  54. data/lib/reactor_sdk/resources/extension_package_usage_authorization.rb +26 -0
  55. data/lib/reactor_sdk/resources/host.rb +68 -0
  56. data/lib/reactor_sdk/resources/library.rb +67 -0
  57. data/lib/reactor_sdk/resources/library_comparison.rb +72 -0
  58. data/lib/reactor_sdk/resources/library_comparison_entry.rb +144 -0
  59. data/lib/reactor_sdk/resources/library_snapshot.rb +118 -0
  60. data/lib/reactor_sdk/resources/library_snapshot_extension_index.rb +70 -0
  61. data/lib/reactor_sdk/resources/library_snapshot_index.rb +169 -0
  62. data/lib/reactor_sdk/resources/library_with_resources.rb +194 -0
  63. data/lib/reactor_sdk/resources/note.rb +37 -0
  64. data/lib/reactor_sdk/resources/profile.rb +22 -0
  65. data/lib/reactor_sdk/resources/property.rb +44 -0
  66. data/lib/reactor_sdk/resources/revision.rb +156 -0
  67. data/lib/reactor_sdk/resources/rule.rb +44 -0
  68. data/lib/reactor_sdk/resources/rule_component.rb +101 -0
  69. data/lib/reactor_sdk/resources/search_results.rb +28 -0
  70. data/lib/reactor_sdk/resources/secret.rb +17 -0
  71. data/lib/reactor_sdk/resources/upstream_chain.rb +80 -0
  72. data/lib/reactor_sdk/resources/upstream_chain_entry.rb +55 -0
  73. data/lib/reactor_sdk/response_parser.rb +160 -0
  74. data/lib/reactor_sdk/version.rb +5 -0
  75. data/lib/reactor_sdk.rb +79 -0
  76. data/reactor_sdk.gemspec +70 -0
  77. data/sig/reactor_sdk.rbs +346 -0
  78. metadata +293 -0
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file resources/note.rb
5
+ # @description Represents an Adobe Launch Note resource.
6
+ #
7
+ # Notes are textual annotations attached to notable Launch resources such
8
+ # as rules, data elements, libraries, properties, extensions, and rule
9
+ # components.
10
+ #
11
+ # @domain Resources
12
+ #
13
+
14
+ module ReactorSDK
15
+ module Resources
16
+ class Note < BaseResource
17
+ # @return [String] Note body text
18
+ attribute :text
19
+
20
+ # @return [String] Display name of the note author
21
+ attribute :author_display_name
22
+
23
+ # @return [String] Email of the note author
24
+ attribute :author_email
25
+
26
+ # @return [String] ISO8601 timestamp when the note was created
27
+ attribute :created_at
28
+
29
+ ##
30
+ # @return [String] Human-readable representation
31
+ #
32
+ def inspect
33
+ "#<ReactorSDK::Resources::Note id=#{id.inspect} text=#{text.inspect}>"
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactorSDK
4
+ module Resources
5
+ class Profile < BaseResource
6
+ attribute :active_org
7
+ attribute :expires_in
8
+ attribute :display_name
9
+ attribute :job_function
10
+ attribute :email
11
+ attribute :organizations, default: {}
12
+
13
+ def rights
14
+ Array(meta['rights'])
15
+ end
16
+
17
+ def inspect
18
+ "#<ReactorSDK::Resources::Profile id=#{id.inspect} email=#{email.inspect}>"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file resources/property.rb
5
+ # @description Represents an Adobe Launch Property resource.
6
+ #
7
+ # A Property is the primary container in Adobe Launch. All rules,
8
+ # data elements, extensions, environments, and libraries belong
9
+ # to a property. A company can have many properties.
10
+ #
11
+ # @domain Resources
12
+ # @see https://developer.adobe.com/experience-platform/documentation/tags/api/endpoints/properties/
13
+ #
14
+
15
+ module ReactorSDK
16
+ module Resources
17
+ class Property < BaseResource
18
+ # @return [String] Display name of the property
19
+ attribute :name
20
+
21
+ # @return [String] Platform type — one of: "web", "mobile", "edge"
22
+ attribute :platform
23
+
24
+ # @return [Boolean] Whether the property is enabled
25
+ attribute :enabled, as: :boolean
26
+
27
+ # @return [Array<String>] Domains associated with this property (web only)
28
+ attribute :domains, default: []
29
+
30
+ # @return [String] ISO8601 timestamp when the property was created
31
+ attribute :created_at
32
+
33
+ # @return [String] ISO8601 timestamp when the property was last updated
34
+ attribute :updated_at
35
+
36
+ ##
37
+ # @return [String] Human-readable representation
38
+ #
39
+ def inspect
40
+ "#<ReactorSDK::Resources::Property id=#{id.inspect} name=#{name.inspect} platform=#{platform.inspect}>"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,156 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file resources/revision.rb
5
+ # @description Represents an Adobe Launch Revision resource.
6
+ #
7
+ # Revisions are point-in-time snapshots of any revisable resource —
8
+ # rules, data elements, and extensions. Every time a revisable resource
9
+ # is saved, Adobe creates a new revision capturing its full state at
10
+ # that moment.
11
+ #
12
+ # Revisions are the foundation of LaunchGuard's diff engine. By fetching
13
+ # the revision from each library and comparing the two snapshots, the
14
+ # exact field-level changes between versions can be determined.
15
+ #
16
+ # The full resource snapshot is returned in the JSON:API `included`
17
+ # array when fetching a revision with `GET /revisions/:id`. This class
18
+ # extracts that snapshot and exposes it alongside the revision metadata.
19
+ #
20
+ # Upstream resolution: when a resource does not exist in the target
21
+ # library, the app walks upstream through the environment chain
22
+ # (Development → Staging → Production) to find the nearest version
23
+ # to diff against. The SDK provides the data — the app owns this logic.
24
+ #
25
+ # @domain Resources
26
+ # @see https://developer.adobe.com/experience-platform/documentation/tags/api/endpoints/revisions/
27
+ #
28
+
29
+ module ReactorSDK
30
+ module Resources
31
+ class Revision < BaseResource
32
+ # @return [String] ISO8601 timestamp when this revision was created
33
+ attribute :created_at
34
+
35
+ # @return [String, nil] The action that triggered this revision
36
+ # Common values: "created", "updated", "published", "rejected"
37
+ attribute :activity_type
38
+
39
+ ##
40
+ # Returns the full attributes snapshot of the resource at this revision.
41
+ #
42
+ # Adobe returns the revisioned resource in the JSON:API `included` array
43
+ # when fetching a revision. This method extracts those attributes so the
44
+ # app can compare two snapshots field by field.
45
+ #
46
+ # Returns an empty Hash if the included snapshot is not present —
47
+ # this happens when fetching a revision list (GET /rules/:id/revisions)
48
+ # rather than a single revision (GET /revisions/:id). Always use
49
+ # revisions.find(id) when you need the full snapshot.
50
+ #
51
+ # @return [Hash] Full attributes of the revisioned resource, or {} if absent
52
+ #
53
+ def entity_snapshot
54
+ return {} if @included_entity.nil?
55
+
56
+ @included_entity.fetch('attributes', {})
57
+ end
58
+
59
+ ##
60
+ # Returns the full relationships snapshot of the resource at this revision.
61
+ #
62
+ # @return [Hash]
63
+ #
64
+ def entity_relationships
65
+ return {} if @included_entity.nil?
66
+
67
+ @included_entity.fetch('relationships', {})
68
+ end
69
+
70
+ ##
71
+ # Returns the Adobe ID of the resource this revision belongs to.
72
+ # Extracted from the JSON:API relationships on the revision.
73
+ #
74
+ # @return [String, nil] Resource ID (e.g. "RL123") or nil if not present
75
+ #
76
+ attr_reader :entity_id
77
+
78
+ ##
79
+ # Returns the JSON:API type of the resource this revision belongs to.
80
+ # Extracted from the JSON:API relationships on the revision.
81
+ #
82
+ # @return [String, nil] Resource type (e.g. "rules") or nil if not present
83
+ #
84
+ attr_reader :entity_type
85
+
86
+ ##
87
+ # Overrides BaseResource initializer to extract the included entity
88
+ # and relationship data from the raw JSON:API response.
89
+ #
90
+ # In addition to standard id/type/attributes/meta, the Revision resource
91
+ # accepts two extra keyword arguments:
92
+ # - included_entity: the raw included resource hash from the API response
93
+ # - relationships: the relationships hash from the revision data object
94
+ #
95
+ # These are passed by the ResponseParser when building a Revision from
96
+ # a full GET /revisions/:id response.
97
+ #
98
+ # @param id [String] Adobe revision ID
99
+ # @param type [String] JSON:API type ("revisions")
100
+ # @param attributes [Hash] Revision attributes
101
+ # @param meta [Hash] Optional metadata
102
+ # @param included_entity [Hash, nil] Raw included resource from API response
103
+ # @param relationships [Hash, nil] Relationships hash from the revision
104
+ #
105
+ def initialize(
106
+ id:,
107
+ type:,
108
+ attributes: {},
109
+ meta: {},
110
+ relationships: {},
111
+ included_entity: nil,
112
+ revision_relationships: nil
113
+ )
114
+ super(
115
+ id: id,
116
+ type: type,
117
+ attributes: attributes,
118
+ meta: meta,
119
+ relationships: relationships
120
+ )
121
+ @included_entity = included_entity
122
+ extract_entity_identity(revision_relationships || relationships)
123
+ end
124
+
125
+ ##
126
+ # @return [String] Human-readable representation
127
+ #
128
+ def inspect
129
+ '#<ReactorSDK::Resources::Revision ' \
130
+ "id=#{id.inspect} " \
131
+ "activity_type=#{activity_type.inspect} " \
132
+ "entity_id=#{entity_id.inspect} " \
133
+ "entity_type=#{entity_type.inspect}>"
134
+ end
135
+
136
+ private
137
+
138
+ ##
139
+ # Extracts the entity ID and type from the revision's relationships hash.
140
+ # Adobe stores the revisioned resource reference under relationships.entity.data.
141
+ #
142
+ # @param relationships [Hash, nil] The relationships object from the API response
143
+ # @sideeffect Sets @entity_id and @entity_type
144
+ #
145
+ def extract_entity_identity(relationships)
146
+ return unless relationships.is_a?(Hash)
147
+
148
+ entity_data = relationships.dig('entity', 'data')
149
+ return unless entity_data.is_a?(Hash)
150
+
151
+ @entity_id = entity_data['id']
152
+ @entity_type = entity_data['type']
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file resources/rule.rb
5
+ # @description Represents an Adobe Launch Rule resource.
6
+ #
7
+ # Rules define the logic that Adobe Launch executes — they consist
8
+ # of conditions (when to run) and actions (what to do). Rules belong
9
+ # to a property and are versioned via the revisions endpoint.
10
+ #
11
+ # @domain Resources
12
+ # @see https://developer.adobe.com/experience-platform/documentation/tags/api/endpoints/rules/
13
+ #
14
+
15
+ module ReactorSDK
16
+ module Resources
17
+ class Rule < BaseResource
18
+ # @return [String] Display name of the rule
19
+ attribute :name
20
+
21
+ # @return [Boolean] Whether the rule is enabled
22
+ attribute :enabled, as: :boolean
23
+
24
+ # @return [String] ISO8601 timestamp when the rule was created
25
+ attribute :created_at
26
+
27
+ # @return [String] ISO8601 timestamp when the rule was last updated
28
+ attribute :updated_at
29
+
30
+ # @return [String, nil] ISO8601 timestamp when the rule was last published
31
+ attribute :published_at
32
+
33
+ # @return [String, nil] ISO8601 timestamp when the rule was last revised
34
+ attribute :revised_at
35
+
36
+ ##
37
+ # @return [String] Human-readable representation
38
+ #
39
+ def inspect
40
+ "#<ReactorSDK::Resources::Rule id=#{id.inspect} name=#{name.inspect} enabled=#{enabled.inspect}>"
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file resources/rule_component.rb
5
+ # @description Represents an Adobe Launch Rule Component resource.
6
+ #
7
+ # Rule components are the individual conditions and actions that make
8
+ # up a rule. Each component references a delegate (an extension-provided
9
+ # function) via its delegate_descriptor_id and carries a settings hash
10
+ # specific to that delegate.
11
+ #
12
+ # The settings field varies significantly across extension types:
13
+ # - Core custom code actions store JavaScript or HTML in settings["source"]
14
+ # - Adobe Web SDK actions store XDM objects and data objects
15
+ # - Adobe Analytics actions store variable mappings
16
+ # - Third-party extensions define their own settings structure
17
+ #
18
+ # Use parsed_settings to access the full settings object as a Ruby Hash.
19
+ # This is the primary accessor for component configuration — it covers
20
+ # all extension types uniformly, exactly as Adobe Launch displays settings
21
+ # in its own version comparison UI.
22
+ #
23
+ # @domain Resources
24
+ # @see https://developer.adobe.com/experience-platform/documentation/tags/api/endpoints/rule-components/
25
+ #
26
+
27
+ module ReactorSDK
28
+ module Resources
29
+ class RuleComponent < BaseResource
30
+ # @return [String] Display name of the rule component
31
+ attribute :name
32
+
33
+ # @return [String] Identifies the extension delegate powering this component
34
+ # Format: "extension-package-name::component-type::component-name"
35
+ # Example: "core::actions::custom-code"
36
+ # Example: "adobe-alloy::actions::send-event"
37
+ attribute :delegate_descriptor_id
38
+
39
+ # @return [String] Raw settings value exactly as returned by Adobe.
40
+ # May be a JSON-encoded string or a plain Hash depending on the extension.
41
+ # Use parsed_settings for reliable Hash access.
42
+ attribute :settings
43
+
44
+ # @return [Integer, nil] Execution order of this component within the rule
45
+ attribute :order
46
+
47
+ # @return [Float, Integer, nil] Execution order of this component within the rule graph
48
+ attribute :rule_order
49
+
50
+ # @return [String] ISO8601 timestamp when the component was created
51
+ attribute :created_at
52
+
53
+ # @return [String] ISO8601 timestamp when the component was last updated
54
+ attribute :updated_at
55
+
56
+ ##
57
+ # Returns the settings field parsed into a Ruby Hash.
58
+ #
59
+ # This is the primary accessor for component configuration. It handles
60
+ # all extension types uniformly:
61
+ # - Core custom code (JavaScript, HTML) stored as JSON-encoded string
62
+ # - Adobe Web SDK XDM objects and data objects
63
+ # - Adobe Analytics variable mappings and custom setup blocks
64
+ # - Any third-party extension settings structure
65
+ #
66
+ # The app can render this as formatted JSON for display and diffing —
67
+ # exactly as Adobe Launch does in its own version comparison UI.
68
+ #
69
+ # Behaviour by input type:
70
+ # - JSON-encoded string → parsed into Hash
71
+ # - Already a Hash → returned as-is
72
+ # - nil or blank → returns empty Hash
73
+ # - Unparseable string → returns empty Hash, raw value still on settings
74
+ #
75
+ # The raw settings value is always preserved on the settings attribute
76
+ # unchanged — this method never modifies the underlying data.
77
+ #
78
+ # @return [Hash] Parsed settings or empty hash if nil, blank, or unparseable
79
+ #
80
+ def parsed_settings
81
+ raw = @attributes['settings']
82
+ return {} if raw.nil? || raw == ''
83
+ return raw if raw.is_a?(Hash)
84
+
85
+ JSON.parse(raw)
86
+ rescue JSON::ParserError
87
+ {}
88
+ end
89
+
90
+ ##
91
+ # @return [String] Human-readable representation
92
+ #
93
+ def inspect
94
+ '#<ReactorSDK::Resources::RuleComponent ' \
95
+ "id=#{id.inspect} " \
96
+ "name=#{name.inspect} " \
97
+ "delegate=#{delegate_descriptor_id.inspect}>"
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactorSDK
4
+ module Resources
5
+ class SearchResults
6
+ include Enumerable
7
+
8
+ attr_reader :results, :meta
9
+
10
+ def initialize(results:, meta: {})
11
+ @results = results
12
+ @meta = meta
13
+ end
14
+
15
+ def each(&)
16
+ results.each(&)
17
+ end
18
+
19
+ def total_hits
20
+ meta.fetch('total_hits', results.length)
21
+ end
22
+
23
+ def inspect
24
+ "#<ReactorSDK::Resources::SearchResults total_hits=#{total_hits} size=#{results.length}>"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactorSDK
4
+ module Resources
5
+ class Secret < BaseResource
6
+ attribute :name
7
+ attribute :type_of
8
+ attribute :credentials, default: {}
9
+ attribute :created_at
10
+ attribute :updated_at
11
+
12
+ def inspect
13
+ "#<ReactorSDK::Resources::Secret id=#{id.inspect} name=#{name.inspect} type_of=#{type_of.inspect}>"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file resources/upstream_chain.rb
5
+ # @description Represents the full upstream lookup result for one resource.
6
+ #
7
+ # This wrapper captures the target library context and the ordered upstream
8
+ # entries that were inspected. It exists so callers can ask higher-level
9
+ # questions such as:
10
+ # - What revision does the target library currently contain?
11
+ # - Which upstream library is the nearest match?
12
+ # - Did the resource disappear entirely upstream?
13
+ #
14
+
15
+ module ReactorSDK
16
+ module Resources
17
+ class UpstreamChain
18
+ include Enumerable
19
+
20
+ attr_reader :resource_id,
21
+ :resource_type,
22
+ :property_id,
23
+ :target_library_id,
24
+ :target_resource,
25
+ :target_revision_id,
26
+ :entries
27
+
28
+ def initialize(
29
+ resource_id:,
30
+ resource_type:,
31
+ property_id:,
32
+ target_library_id:,
33
+ target_resource:,
34
+ target_revision_id:,
35
+ entries:
36
+ )
37
+ @resource_id = resource_id
38
+ @resource_type = resource_type
39
+ @property_id = property_id
40
+ @target_library_id = target_library_id
41
+ @target_resource = target_resource
42
+ @target_revision_id = target_revision_id
43
+ @entries = Array(entries)
44
+ end
45
+
46
+ ##
47
+ # @yieldparam entry [ReactorSDK::Resources::UpstreamChainEntry]
48
+ # @return [Array<ReactorSDK::Resources::UpstreamChainEntry>]
49
+ #
50
+ def each(&)
51
+ @entries.each(&)
52
+ end
53
+
54
+ ##
55
+ # @return [ReactorSDK::Resources::UpstreamChainEntry, nil]
56
+ #
57
+ def nearest_match
58
+ @entries.find(&:present?)
59
+ end
60
+
61
+ ##
62
+ # @return [Boolean] true when any upstream library contains the resource
63
+ #
64
+ def found?
65
+ !nearest_match.nil?
66
+ end
67
+
68
+ ##
69
+ # @return [String] Human-readable representation
70
+ #
71
+ def inspect
72
+ '#<ReactorSDK::Resources::UpstreamChain ' \
73
+ "resource_id=#{resource_id.inspect} " \
74
+ "resource_type=#{resource_type.inspect} " \
75
+ "target_library_id=#{target_library_id.inspect} " \
76
+ "entries=#{entries.length}>"
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file resources/upstream_chain_entry.rb
5
+ # @description Represents one upstream-library lookup for a single resource.
6
+ #
7
+ # This object is not returned directly by the Adobe API. It is assembled by
8
+ # ReactorSDK when resolving a resource across the ordered upstream library
9
+ # chain. Each entry answers:
10
+ # - which library was inspected
11
+ # - which stage that library belongs to
12
+ # - whether the resource exists in that library
13
+ # - which revision ID and revision snapshot were found
14
+ #
15
+
16
+ module ReactorSDK
17
+ module Resources
18
+ class UpstreamChainEntry
19
+ attr_reader :library, :stage, :resource, :revision_id, :revision
20
+
21
+ def initialize(library:, stage:, resource:, revision_id:, revision:)
22
+ @library = library
23
+ @stage = stage
24
+ @resource = resource
25
+ @revision_id = revision_id
26
+ @revision = revision
27
+ end
28
+
29
+ ##
30
+ # @return [Boolean] true when the resource exists in this upstream library
31
+ #
32
+ def present?
33
+ !@resource.nil?
34
+ end
35
+
36
+ ##
37
+ # @return [Hash, nil] Point-in-time snapshot for the matched revision
38
+ #
39
+ def entity_snapshot
40
+ @revision&.entity_snapshot
41
+ end
42
+
43
+ ##
44
+ # @return [String] Human-readable representation
45
+ #
46
+ def inspect
47
+ '#<ReactorSDK::Resources::UpstreamChainEntry ' \
48
+ "library_id=#{library.id.inspect} " \
49
+ "stage=#{stage.inspect} " \
50
+ "resource_id=#{resource&.id.inspect} " \
51
+ "revision_id=#{revision_id.inspect}>"
52
+ end
53
+ end
54
+ end
55
+ end