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,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file rate_limiter.rb
5
+ # @description Token bucket rate limiter for Reactor API requests.
6
+ #
7
+ # Adobe enforces a limit of 120 requests per minute per access token.
8
+ # This class implements a token bucket algorithm — the bucket starts
9
+ # full and refills proportionally over time. When empty, the caller
10
+ # blocks until a token is available.
11
+ #
12
+ # One RateLimiter instance is created per ReactorSDK::Client so that
13
+ # different client instances do not share a limit.
14
+ #
15
+ # @domain Infrastructure
16
+ #
17
+
18
+ module ReactorSDK
19
+ class RateLimiter
20
+ # Adobe's documented rate limit per access token
21
+ MAX_REQUESTS_PER_MINUTE = 120
22
+
23
+ # The window over which the limit applies
24
+ INTERVAL_SECONDS = 60.0
25
+
26
+ ##
27
+ # Initializes a full token bucket.
28
+ # The first MAX_REQUESTS_PER_MINUTE calls proceed without any delay.
29
+ #
30
+ def initialize
31
+ @mutex = Mutex.new
32
+ @tokens = MAX_REQUESTS_PER_MINUTE
33
+ @last_tick = Time.now.utc
34
+ end
35
+
36
+ ##
37
+ # Acquires one token from the bucket, blocking if the bucket is empty.
38
+ # Refills the bucket based on elapsed time before checking availability.
39
+ #
40
+ # @return [void]
41
+ #
42
+ def acquire
43
+ @mutex.synchronize do
44
+ refill
45
+ if @tokens >= 1
46
+ @tokens -= 1
47
+ else
48
+ sleep(seconds_per_token)
49
+ refill
50
+ @tokens -= 1
51
+ end
52
+ end
53
+ end
54
+
55
+ ##
56
+ # Returns the number of tokens currently available.
57
+ # Useful for monitoring and testing — not used internally by acquire.
58
+ #
59
+ # @return [Integer] Current token count
60
+ #
61
+ def available_tokens
62
+ @mutex.synchronize do
63
+ refill
64
+ @tokens.floor
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ ##
71
+ # Adds tokens proportional to time elapsed since the last tick.
72
+ # Never exceeds MAX_REQUESTS_PER_MINUTE.
73
+ #
74
+ # @sideeffect Updates @tokens and @last_tick
75
+ #
76
+ def refill
77
+ now = Time.now.utc
78
+ elapsed = now - @last_tick
79
+ new_tokens = (elapsed / INTERVAL_SECONDS) * MAX_REQUESTS_PER_MINUTE
80
+
81
+ return unless new_tokens >= 1
82
+
83
+ @tokens = [@tokens + new_tokens.floor, MAX_REQUESTS_PER_MINUTE].min
84
+ @last_tick = now
85
+ end
86
+
87
+ ##
88
+ # Calculates how long to wait for a single token to become available.
89
+ #
90
+ # @return [Float] Seconds to sleep
91
+ #
92
+ def seconds_per_token
93
+ INTERVAL_SECONDS / MAX_REQUESTS_PER_MINUTE
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactorSDK
4
+ module ReferenceExtractor
5
+ DATA_ELEMENT_TOKEN_PATTERN = /%([^%\r\n]+)%/
6
+ GET_VAR_PATTERN = /_satellite\.getVar\(\s*(['"])(.*?)\1\s*\)/
7
+
8
+ module_function
9
+
10
+ def extract_data_element_names(resource)
11
+ names = Set.new
12
+
13
+ collect_string_references(resource.parsed_settings, names) if resource.respond_to?(:parsed_settings)
14
+
15
+ raw_settings = resource.respond_to?(:settings) ? resource.settings : nil
16
+ collect_string_references(raw_settings, names) if raw_settings.is_a?(String)
17
+
18
+ names.to_a
19
+ end
20
+
21
+ def collect_string_references(value, names)
22
+ case value
23
+ when String
24
+ value.scan(DATA_ELEMENT_TOKEN_PATTERN) { |match| names << match.first }
25
+ value.scan(GET_VAR_PATTERN) { |match| names << match.last }
26
+ when Array
27
+ value.each { |item| collect_string_references(item, names) }
28
+ when Hash
29
+ value.each_value { |item| collect_string_references(item, names) }
30
+ end
31
+ end
32
+ private_class_method :collect_string_references
33
+ end
34
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactorSDK
4
+ module ResourceMetadata
5
+ module_function
6
+
7
+ def summary(resource)
8
+ decorate!(
9
+ {
10
+ 'id' => resource.id,
11
+ 'type' => resource.type
12
+ },
13
+ resource
14
+ )
15
+ end
16
+
17
+ def base_payload(resource, kind:, attributes:, launch_raw:)
18
+ decorate!(
19
+ {
20
+ 'kind' => kind,
21
+ 'id' => resource.id,
22
+ 'attributes' => attributes,
23
+ 'launch_raw' => launch_raw
24
+ },
25
+ resource,
26
+ include_position: false,
27
+ include_revision: false
28
+ )
29
+ end
30
+
31
+ def delegate_descriptor(resource)
32
+ return '' unless resource.respond_to?(:delegate_descriptor_id)
33
+
34
+ resource.delegate_descriptor_id.to_s
35
+ end
36
+
37
+ def revision_id_for(resource)
38
+ return resource.revision_id if resource.respond_to?(:revision_id)
39
+ return resource.relationship_id('latest_revision') if resource.respond_to?(:relationship_id)
40
+
41
+ nil
42
+ end
43
+
44
+ def decorate!(payload, resource, include_position: true, include_revision: true)
45
+ add_name(payload, resource)
46
+ add_delegate_descriptor(payload, resource)
47
+ add_position_fields(payload, resource) if include_position
48
+ add_revision_id(payload, resource) if include_revision
49
+
50
+ payload
51
+ end
52
+
53
+ def add_name(payload, resource)
54
+ payload['name'] = resource.name if resource.respond_to?(:name)
55
+ end
56
+
57
+ def add_delegate_descriptor(payload, resource)
58
+ return unless resource.respond_to?(:delegate_descriptor_id)
59
+
60
+ payload['delegate_descriptor_id'] = resource.delegate_descriptor_id
61
+ end
62
+
63
+ def add_position_fields(payload, resource)
64
+ payload['order'] = resource.order if resource.respond_to?(:order) && !resource.order.nil?
65
+ payload['rule_order'] = resource.rule_order if resource.respond_to?(:rule_order) && !resource.rule_order.nil?
66
+ end
67
+
68
+ def add_revision_id(payload, resource)
69
+ revision_id = revision_id_for(resource)
70
+ payload['revision_id'] = revision_id if revision_id
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactorSDK
4
+ module ResourceNormalizer
5
+ CUSTOM_CODE_PATTERN = /::custom-code\z/i
6
+ ADOBE_ALLOY_PATTERN = /\Aadobe-alloy::/i
7
+ ADOBE_ANALYTICS_PATTERN = /\Aadobe-analytics::/i
8
+
9
+ module_function
10
+
11
+ def normalize_resource(resource)
12
+ configuration, status = normalize_configuration(resource)
13
+
14
+ ReactorSDK::ResourceMetadata.base_payload(
15
+ resource,
16
+ kind: kind_for(resource),
17
+ attributes: resource.attributes.except('settings'),
18
+ launch_raw: resource.to_h
19
+ ).merge(
20
+ 'configuration' => configuration,
21
+ 'normalization_status' => status
22
+ )
23
+ end
24
+
25
+ def summary(resource)
26
+ ReactorSDK::ResourceMetadata.summary(resource)
27
+ end
28
+
29
+ def to_json(payload)
30
+ JSON.pretty_generate(payload)
31
+ end
32
+
33
+ def kind_for(resource)
34
+ case resource.type
35
+ when 'data_elements' then 'data_element'
36
+ when 'rule_components' then 'rule_component'
37
+ else
38
+ resource.type.sub(/s\z/, '')
39
+ end
40
+ end
41
+
42
+ def normalize_configuration(resource)
43
+ return [nil, 'none'] unless resource.respond_to?(:settings)
44
+
45
+ parsed = resource.respond_to?(:parsed_settings) ? resource.parsed_settings : {}
46
+ return [nil, 'none'] if parsed.empty? && blank_settings?(resource.settings)
47
+
48
+ normalize_delegate_configuration(
49
+ ReactorSDK::ResourceMetadata.delegate_descriptor(resource),
50
+ parsed,
51
+ resource
52
+ )
53
+ rescue JSON::ParserError
54
+ [resource.settings, 'raw']
55
+ end
56
+
57
+ def normalize_custom_code(parsed, resource)
58
+ language = parsed['language']
59
+ language = 'javascript' if language.nil? && resource.type == 'data_elements'
60
+
61
+ normalized = {}
62
+ normalized['language'] = language if language
63
+ normalized['source'] = parsed['source'] if parsed.key?('source')
64
+
65
+ parsed.each do |key, value|
66
+ next if %w[language source].include?(key)
67
+
68
+ normalized[key] = value
69
+ end
70
+
71
+ normalized
72
+ end
73
+
74
+ def blank_settings?(settings)
75
+ settings.nil? || settings == ''
76
+ end
77
+
78
+ def normalize_delegate_configuration(delegate, parsed, resource)
79
+ return [normalize_custom_code(parsed, resource), 'normalized'] if delegate.match?(CUSTOM_CODE_PATTERN)
80
+ return [parsed, 'normalized'] if delegate.match?(ADOBE_ALLOY_PATTERN)
81
+ return [parsed, 'normalized'] if delegate.match?(ADOBE_ANALYTICS_PATTERN)
82
+ return [parsed, 'parsed'] unless parsed.empty?
83
+
84
+ [resource.settings, 'raw']
85
+ end
86
+
87
+ private_class_method :kind_for, :normalize_configuration, :normalize_custom_code, :blank_settings?,
88
+ :normalize_delegate_configuration
89
+ end
90
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactorSDK
4
+ module Resources
5
+ class AppConfiguration < BaseResource
6
+ attribute :name
7
+ attribute :app_id
8
+ attribute :platform
9
+ attribute :messaging_service
10
+ attribute :key_type
11
+ attribute :push_credential, default: {}
12
+ attribute :created_at
13
+ attribute :updated_at
14
+
15
+ def inspect
16
+ "#<ReactorSDK::Resources::AppConfiguration id=#{id.inspect} name=#{name.inspect}>"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file resources/audit_event.rb
5
+ # @description Represents an Adobe Launch Audit Event resource.
6
+ #
7
+ # Audit events record every significant action taken within Adobe Launch —
8
+ # creates, updates, deletes, publishes, and state transitions.
9
+ # LaunchGuard syncs these events into its own audit log to provide a
10
+ # complete cross-platform activity record.
11
+ #
12
+ # @domain Resources
13
+ # @see https://developer.adobe.com/experience-platform/documentation/tags/api/endpoints/audit-events/
14
+ #
15
+
16
+ module ReactorSDK
17
+ module Resources
18
+ class AuditEvent < BaseResource
19
+ # @return [String] The type of action that occurred
20
+ attribute :type_of
21
+
22
+ # @return [String] Human-readable name of the affected resource
23
+ attribute :entity_display_name
24
+
25
+ # @return [String] ISO8601 timestamp when the event occurred
26
+ attribute :created_at
27
+
28
+ # @return [Hash, nil] Snapshot of the resource before the action
29
+ attribute :previous_attributes
30
+
31
+ # @return [Hash, nil] Snapshot of the resource after the action
32
+ attribute :updated_attributes
33
+
34
+ ##
35
+ # @return [String] Human-readable representation
36
+ #
37
+ def inspect
38
+ '#<ReactorSDK::Resources::AuditEvent ' \
39
+ "id=#{id.inspect} " \
40
+ "type=#{type_of.inspect} " \
41
+ "entity=#{entity_display_name.inspect}>"
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file resources/base_resource.rb
5
+ # @description Base class for all Adobe Launch resource objects.
6
+ #
7
+ # Provides a class-level `attribute` macro that subclasses use to declare
8
+ # which JSON:API attributes should be exposed as first-class Ruby methods.
9
+ #
10
+ # Instead of accessing raw hash values like:
11
+ # property.attributes["name"]
12
+ # property["platform"]
13
+ #
14
+ # Subclasses declare their fields and callers use clean dot notation:
15
+ # property.name
16
+ # property.platform
17
+ # property.enabled? # boolean fields get a ? alias automatically
18
+ #
19
+ # Usage in a subclass:
20
+ # class Property < BaseResource
21
+ # attribute :name
22
+ # attribute :platform
23
+ # attribute :enabled, as: :boolean
24
+ # attribute :domains, default: []
25
+ # attribute :created_at
26
+ # end
27
+ #
28
+ # @domain Resources
29
+ #
30
+
31
+ module ReactorSDK
32
+ module Resources
33
+ class BaseResource
34
+ # @return [String] Adobe resource ID (e.g. "PR1234abcd...")
35
+ attr_reader :id
36
+
37
+ # @return [String] JSON:API resource type (e.g. "rules", "properties")
38
+ attr_reader :type
39
+
40
+ # @return [Hash] Full raw attributes hash from the JSON:API response
41
+ # Available for accessing fields not declared with the attribute macro
42
+ attr_reader :attributes
43
+
44
+ # @return [Hash] Meta hash from the JSON:API response
45
+ attr_reader :meta
46
+
47
+ # @return [Hash] Relationships hash from the JSON:API response
48
+ attr_reader :relationships
49
+
50
+ ##
51
+ # Class-level macro for declaring typed attribute readers.
52
+ # Called in subclass bodies to define which JSON:API attributes
53
+ # are exposed as Ruby methods on the resource object.
54
+ #
55
+ # @param name [Symbol] Attribute name — must match the JSON:API field name
56
+ # @param as [Symbol] Type cast — :boolean adds a ? method alias (optional)
57
+ # @param default [Object] Default value when the attribute is nil (optional)
58
+ #
59
+ # @example Declare a plain string attribute
60
+ # attribute :name
61
+ #
62
+ # @example Declare a boolean attribute (adds enabled? alias)
63
+ # attribute :enabled, as: :boolean
64
+ #
65
+ # @example Declare an array attribute with a default
66
+ # attribute :domains, default: []
67
+ #
68
+ def self.attribute(name, as: nil, default: nil)
69
+ # Define the reader method that pulls from the attributes hash
70
+ define_method(name) do
71
+ value = @attributes[name.to_s]
72
+ value.nil? ? default : value
73
+ end
74
+
75
+ # Boolean fields get a ? alias automatically
76
+ # e.g. attribute :enabled, as: :boolean
77
+ # generates both enabled and enabled?
78
+ define_method(:"#{name}?") { !!public_send(name) } if as == :boolean
79
+ end
80
+
81
+ ##
82
+ # @param id [String] Adobe resource ID
83
+ # @param type [String] JSON:API resource type
84
+ # @param attributes [Hash] Resource attribute values from the API response
85
+ # @param meta [Hash] Optional metadata from the API response
86
+ # @param relationships [Hash] Optional relationships from the API response
87
+ #
88
+ def initialize(id:, type:, attributes: {}, meta: {}, relationships: {})
89
+ @id = id
90
+ @type = type
91
+ @attributes = attributes
92
+ @meta = meta
93
+ @relationships = relationships
94
+ end
95
+
96
+ ##
97
+ # Provides fallback access to any attribute by name.
98
+ # Use this for attributes not declared with the attribute macro,
99
+ # or for dynamic access patterns.
100
+ #
101
+ # @param key [String, Symbol] Attribute name
102
+ # @return [Object, nil] Attribute value or nil if not present
103
+ #
104
+ def [](key)
105
+ @attributes[key.to_s]
106
+ end
107
+
108
+ ##
109
+ # Returns the raw relationship object for a given relationship name.
110
+ #
111
+ # @param name [String, Symbol]
112
+ # @return [Hash, nil]
113
+ #
114
+ def relationship_data(name)
115
+ @relationships[name.to_s]
116
+ end
117
+
118
+ ##
119
+ # Returns the related resource ID when the relationship contains a single linkage.
120
+ #
121
+ # @param name [String, Symbol]
122
+ # @return [String, nil]
123
+ #
124
+ def relationship_id(name)
125
+ relationship_data(name)&.dig('data', 'id')
126
+ end
127
+
128
+ ##
129
+ # Returns related resource IDs when the relationship contains collection linkage.
130
+ #
131
+ # @param name [String, Symbol]
132
+ # @return [Array<String>]
133
+ #
134
+ def relationship_ids(name)
135
+ data = relationship_data(name)&.fetch('data', nil)
136
+ return [] unless data.is_a?(Array)
137
+
138
+ data.filter_map { |item| item['id'] }
139
+ end
140
+
141
+ ##
142
+ # Returns a readable string representation for debugging.
143
+ # Subclasses override this to include their most useful fields.
144
+ #
145
+ # @return [String]
146
+ #
147
+ def inspect
148
+ "#<#{self.class.name} id=#{@id.inspect} type=#{@type.inspect}>"
149
+ end
150
+
151
+ ##
152
+ # Two resources are equal if they represent the same Adobe resource —
153
+ # same id and same type, regardless of which attributes were loaded.
154
+ #
155
+ # @param other [Object] Object to compare with
156
+ # @return [Boolean]
157
+ #
158
+ def ==(other)
159
+ other.is_a?(BaseResource) &&
160
+ other.id == id &&
161
+ other.type == type
162
+ end
163
+
164
+ ##
165
+ # Returns a plain hash representation of the resource.
166
+ # Useful for serialisation, logging, and debugging.
167
+ #
168
+ # @return [Hash]
169
+ #
170
+ def to_h
171
+ {
172
+ id: @id,
173
+ type: @type,
174
+ attributes: @attributes,
175
+ meta: @meta,
176
+ relationships: @relationships
177
+ }
178
+ end
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file resources/build.rb
5
+ # @description Represents an Adobe Launch Build resource.
6
+ #
7
+ # A build is the compiled output of a library — the JavaScript bundle
8
+ # that gets deployed to an environment. Builds are created by triggering
9
+ # a library build and move through statuses: pending -> processing ->
10
+ # succeeded or failed.
11
+ #
12
+ # @domain Resources
13
+ # @see https://developer.adobe.com/experience-platform/documentation/tags/api/endpoints/builds/
14
+ #
15
+
16
+ module ReactorSDK
17
+ module Resources
18
+ class Build < BaseResource
19
+ # @return [String] Current build status
20
+ # One of: "pending", "processing", "succeeded", "failed", "rejected"
21
+ attribute :status
22
+
23
+ # @return [String] ISO8601 timestamp when the build was created
24
+ attribute :created_at
25
+
26
+ # @return [String] ISO8601 timestamp when the build was last updated
27
+ attribute :updated_at
28
+
29
+ ##
30
+ # Returns true if the build completed successfully.
31
+ #
32
+ # @return [Boolean]
33
+ #
34
+ def succeeded?
35
+ status == 'succeeded'
36
+ end
37
+
38
+ ##
39
+ # Returns true if the build is still in progress.
40
+ #
41
+ # @return [Boolean]
42
+ #
43
+ def pending?
44
+ %w[pending processing].include?(status)
45
+ end
46
+
47
+ ##
48
+ # Returns true if the build failed.
49
+ #
50
+ # @return [Boolean]
51
+ #
52
+ def failed?
53
+ status == 'failed'
54
+ end
55
+
56
+ ##
57
+ # @return [String] Human-readable representation
58
+ #
59
+ def inspect
60
+ "#<ReactorSDK::Resources::Build id=#{id.inspect} status=#{status.inspect}>"
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactorSDK
4
+ module Resources
5
+ class Callback < BaseResource
6
+ attribute :url
7
+ attribute :subscriptions, default: []
8
+ attribute :created_at
9
+ attribute :updated_at
10
+
11
+ def inspect
12
+ "#<ReactorSDK::Resources::Callback id=#{id.inspect} url=#{url.inspect}>"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file resources/company.rb
5
+ # @description Represents an Adobe Launch Company resource.
6
+ #
7
+ # A Company maps directly to an Adobe IMS Organisation. It is the
8
+ # top-level container — all properties belong to a company.
9
+ # Most orgs have exactly one company.
10
+ #
11
+ # @domain Resources
12
+ # @see https://developer.adobe.com/experience-platform/documentation/tags/api/endpoints/companies/
13
+ #
14
+
15
+ module ReactorSDK
16
+ module Resources
17
+ class Company < BaseResource
18
+ # @return [String] Display name of the company
19
+ attribute :name
20
+
21
+ # @return [String] Adobe IMS organisation ID
22
+ attribute :org_id
23
+
24
+ # @return [String] ISO8601 timestamp when the company was created
25
+ attribute :created_at
26
+
27
+ # @return [String] ISO8601 timestamp when the company was last updated
28
+ attribute :updated_at
29
+
30
+ ##
31
+ # @return [String] Human-readable representation
32
+ #
33
+ def inspect
34
+ "#<ReactorSDK::Resources::Company id=#{id.inspect} name=#{name.inspect}>"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactorSDK
4
+ module Resources
5
+ class ComprehensiveDataElement < ComprehensiveResource
6
+ attr_reader :referenced_data_elements, :impacted_rules
7
+
8
+ def initialize(resource:, referenced_data_elements:, impacted_rules:)
9
+ super(resource: resource)
10
+ @referenced_data_elements = Array(referenced_data_elements)
11
+ @impacted_rules = Array(impacted_rules)
12
+ end
13
+
14
+ def associated_records
15
+ (@referenced_data_elements + @impacted_rules).uniq
16
+ end
17
+
18
+ def normalized_payload
19
+ payload = normalized_resource_payload
20
+ payload['associations'] = {
21
+ 'referenced_data_elements' => summaries_for(@referenced_data_elements),
22
+ 'impacted_rules' => summaries_for(@impacted_rules)
23
+ }
24
+ payload
25
+ end
26
+ end
27
+ end
28
+ end