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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactorSDK
4
+ module Endpoints
5
+ class Notes < BaseEndpoint
6
+ def find(note_id)
7
+ fetch_resource("/notes/#{note_id}", Resources::Note)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ReactorSDK
4
+ module Endpoints
5
+ class Profiles < BaseEndpoint
6
+ def current
7
+ response = @connection.get('/profile')
8
+ data = response.fetch('data').dup
9
+ data['meta'] = response.fetch('meta', {}).merge(data.fetch('meta', {}))
10
+ @parser.parse(data, Resources::Profile, response: response)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file endpoints/properties.rb
5
+ # @description Endpoint group for Adobe Launch Property resources.
6
+ #
7
+ # Properties are the primary container in Adobe Launch. All rules,
8
+ # data elements, extensions, environments, and libraries belong to
9
+ # a property. A company can have many properties.
10
+ #
11
+ # @domain Endpoints
12
+ # @see https://developer.adobe.com/experience-platform/documentation/tags/api/endpoints/properties/
13
+ #
14
+
15
+ module ReactorSDK
16
+ module Endpoints
17
+ class Properties < BaseEndpoint
18
+ ##
19
+ # Lists all properties for a given company.
20
+ # Follows pagination automatically — returns all properties.
21
+ #
22
+ # @param company_id [String] Adobe company ID (format: "CO" + hex string)
23
+ # @return [Array<ReactorSDK::Resources::Property>]
24
+ # @raise [ReactorSDK::ResourceNotFoundError] if the company does not exist
25
+ # @raise [ReactorSDK::AuthorizationError] if the token cannot access this company
26
+ #
27
+ def list_for_company(company_id)
28
+ list_resources("/companies/#{company_id}/properties", Resources::Property)
29
+ end
30
+
31
+ ##
32
+ # Retrieves a single property by its Adobe ID.
33
+ #
34
+ # @param property_id [String] Adobe property ID (format: "PR" + hex string)
35
+ # @return [ReactorSDK::Resources::Property]
36
+ # @raise [ReactorSDK::ResourceNotFoundError] if the property does not exist
37
+ #
38
+ def find(property_id)
39
+ fetch_resource("/properties/#{property_id}", Resources::Property)
40
+ end
41
+
42
+ ##
43
+ # Retrieves the company that owns a property.
44
+ #
45
+ # @param property_id [String] Adobe property ID
46
+ # @return [ReactorSDK::Resources::Company]
47
+ #
48
+ def company(property_id)
49
+ fetch_resource("/properties/#{property_id}/company", Resources::Company)
50
+ end
51
+
52
+ ##
53
+ # Creates a new property within a company.
54
+ #
55
+ # @param company_id [String] Adobe company ID
56
+ # @param name [String] Display name for the property
57
+ # @param platform [String] One of: "web", "mobile", "edge"
58
+ # @param domains [Array<String>] Domains — required for web properties
59
+ # @return [ReactorSDK::Resources::Property] The newly created property
60
+ # @raise [ReactorSDK::UnprocessableEntityError] if attributes are invalid
61
+ #
62
+ def create(company_id:, name:, platform:, domains: [])
63
+ create_resource(
64
+ "/companies/#{company_id}/properties",
65
+ 'properties',
66
+ Resources::Property,
67
+ attributes: { name: name, platform: platform, domains: domains }
68
+ )
69
+ end
70
+
71
+ ##
72
+ # Updates an existing property.
73
+ #
74
+ # @param property_id [String] Adobe property ID
75
+ # @param attributes [Hash] Fields to update (e.g. { name: "New Name" })
76
+ # @return [ReactorSDK::Resources::Property] The updated property
77
+ # @raise [ReactorSDK::ResourceNotFoundError] if the property does not exist
78
+ #
79
+ def update(property_id, attributes)
80
+ update_resource(
81
+ "/properties/#{property_id}",
82
+ property_id,
83
+ 'properties',
84
+ Resources::Property,
85
+ attributes: attributes
86
+ )
87
+ end
88
+
89
+ ##
90
+ # Deletes a property permanently. This action cannot be undone.
91
+ # All child resources (rules, data elements, environments) are also deleted.
92
+ #
93
+ # @param property_id [String] Adobe property ID
94
+ # @return [nil]
95
+ # @raise [ReactorSDK::ResourceNotFoundError] if the property does not exist
96
+ #
97
+ def delete(property_id)
98
+ delete_resource("/properties/#{property_id}")
99
+ end
100
+
101
+ ##
102
+ # Creates a note on a property.
103
+ #
104
+ # @param property_id [String] Adobe property ID
105
+ # @param text [String] Note body text
106
+ # @return [ReactorSDK::Resources::Note]
107
+ #
108
+ def create_note(property_id, text)
109
+ create_note_for_path("/properties/#{property_id}/notes", text)
110
+ end
111
+
112
+ ##
113
+ # Lists notes attached to a property.
114
+ #
115
+ # @param property_id [String]
116
+ # @return [Array<ReactorSDK::Resources::Note>]
117
+ #
118
+ def list_notes(property_id)
119
+ list_notes_for_path("/properties/#{property_id}/notes")
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file endpoints/revisions.rb
5
+ # @description Endpoint group for Adobe Launch Revision resources.
6
+ #
7
+ # The Reactor API exposes revision history in two different shapes:
8
+ #
9
+ # 1. Resource-scoped revision lists
10
+ # GET /rules/:id/revisions
11
+ # GET /data_elements/:id/revisions
12
+ # GET /extensions/:id/revisions
13
+ # These return versioned resources of the same type as the parent
14
+ # endpoint (Rule, DataElement, Extension), newest first.
15
+ #
16
+ # 2. Generic revision lookups
17
+ # GET /revisions/:id
18
+ # These are used when another endpoint exposes a dedicated
19
+ # `revisions` resource ID, such as a `latest_revision` relationship.
20
+ #
21
+ # In practice this means the list methods below return typed versioned
22
+ # resources, while `find` still resolves an explicit `revisions` ID into
23
+ # a Resources::Revision snapshot wrapper.
24
+ #
25
+ # @domain Endpoints
26
+ # @see https://developer.adobe.com/experience-platform/documentation/tags/api/endpoints/revisions/
27
+ #
28
+
29
+ module ReactorSDK
30
+ module Endpoints
31
+ class Revisions < BaseEndpoint
32
+ ##
33
+ # Retrieves a single generic revision by its Adobe ID.
34
+ #
35
+ # Returns the full revision including the entity snapshot — the complete
36
+ # attributes of the revisioned resource at this point in time. This is
37
+ # the primary method for fetching data needed to build a diff.
38
+ #
39
+ # Calls GET /revisions/:id which returns the revision data alongside
40
+ # the full resource in the included array.
41
+ #
42
+ # Note: this method expects a `revisions` resource ID (for example, an
43
+ # ID surfaced by a `latest_revision` relationship). It does not accept
44
+ # rule, data element, or extension IDs from the resource-scoped
45
+ # `/revisions` list endpoints.
46
+ #
47
+ # @param revision_id [String] Adobe revision ID (format: "RE" + hex string)
48
+ # @return [ReactorSDK::Resources::Revision] Revision with entity_snapshot populated
49
+ # @raise [ReactorSDK::ResourceNotFoundError] if the revision does not exist
50
+ #
51
+ def find(revision_id)
52
+ response = @connection.get("/revisions/#{revision_id}")
53
+ @parser.parse(response['data'], Resources::Revision, response: response)
54
+ end
55
+
56
+ ##
57
+ # Lists all revisions for a given rule, newest first.
58
+ #
59
+ # Returns versioned rule resources, newest first.
60
+ # Follows pagination automatically — returns all revisions.
61
+ #
62
+ # @param rule_id [String] Adobe rule ID (format: "RL" + hex string)
63
+ # @return [Array<ReactorSDK::Resources::Rule>] Versioned rules, newest first
64
+ # @raise [ReactorSDK::ResourceNotFoundError] if the rule does not exist
65
+ #
66
+ def list_for_rule(rule_id)
67
+ records = @paginator.all("/rules/#{rule_id}/revisions")
68
+ @parser.parse_many(records, Resources::Rule)
69
+ end
70
+
71
+ ##
72
+ # Lists all revisions for a given data element, newest first.
73
+ #
74
+ # Returns versioned data element resources, newest first.
75
+ # Follows pagination automatically — returns all revisions.
76
+ #
77
+ # @param data_element_id [String] Adobe data element ID (format: "DE" + hex string)
78
+ # @return [Array<ReactorSDK::Resources::DataElement>] Versioned data elements, newest first
79
+ # @raise [ReactorSDK::ResourceNotFoundError] if the data element does not exist
80
+ #
81
+ def list_for_data_element(data_element_id)
82
+ records = @paginator.all("/data_elements/#{data_element_id}/revisions")
83
+ @parser.parse_many(records, Resources::DataElement)
84
+ end
85
+
86
+ ##
87
+ # Lists all revisions for a given extension, newest first.
88
+ #
89
+ # Returns versioned extension resources, newest first.
90
+ # Follows pagination automatically — returns all revisions.
91
+ #
92
+ # @param extension_id [String] Adobe extension ID (format: "EX" + hex string)
93
+ # @return [Array<ReactorSDK::Resources::Extension>] Versioned extensions, newest first
94
+ # @raise [ReactorSDK::ResourceNotFoundError] if the extension does not exist
95
+ #
96
+ def list_for_extension(extension_id)
97
+ records = @paginator.all("/extensions/#{extension_id}/revisions")
98
+ @parser.parse_many(records, Resources::Extension)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,218 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file endpoints/rule_components.rb
5
+ # @description Endpoint group for Adobe Launch Rule Component resources.
6
+ #
7
+ # Rule components are the individual conditions and actions that make
8
+ # up a rule. Each component references an extension delegate via
9
+ # delegate_descriptor_id and carries a settings hash specific to
10
+ # that delegate.
11
+ #
12
+ # Creating a rule component:
13
+ # - Endpoint: POST /properties/:property_id/rule_components
14
+ # - The rule relationship is passed in the payload, not the URL
15
+ # - Requires extension relationship in the payload
16
+ # - settings must be a JSON-encoded string
17
+ #
18
+ # @domain Endpoints
19
+ # @see https://developer.adobe.com/experience-platform/documentation/tags/api/endpoints/rule-components/
20
+ #
21
+
22
+ module ReactorSDK
23
+ module Endpoints
24
+ class RuleComponents < BaseEndpoint
25
+ ##
26
+ # Lists all components for a given rule.
27
+ # Follows pagination automatically — returns all components.
28
+ #
29
+ # @param rule_id [String] Adobe rule ID
30
+ # @return [Array<ReactorSDK::Resources::RuleComponent>]
31
+ # @raise [ReactorSDK::ResourceNotFoundError] if the rule does not exist
32
+ #
33
+ def list_for_rule(rule_id)
34
+ records = @paginator.all("/rules/#{rule_id}/rule_components")
35
+ records.map { |r| @parser.parse(r, Resources::RuleComponent) }
36
+ end
37
+
38
+ ##
39
+ # Retrieves a single rule component by its Adobe ID.
40
+ #
41
+ # @param rule_component_id [String] Adobe rule component ID (format: "RC" + hex)
42
+ # @return [ReactorSDK::Resources::RuleComponent]
43
+ # @raise [ReactorSDK::ResourceNotFoundError] if the component does not exist
44
+ #
45
+ def find(rule_component_id)
46
+ response = @connection.get("/rule_components/#{rule_component_id}")
47
+ @parser.parse(response['data'], Resources::RuleComponent)
48
+ end
49
+
50
+ ##
51
+ # Creates a new rule component on a property.
52
+ #
53
+ # The component is associated with a rule via the relationships.rules
54
+ # payload — NOT via the URL. The endpoint is always
55
+ # POST /properties/:property_id/rule_components.
56
+ #
57
+ # The delegate_descriptor_id identifies which extension capability
58
+ # powers this component. Examples:
59
+ # "core::actions::custom-code" — Core custom code action
60
+ # "core::conditions::value-comparison" — Core value comparison condition
61
+ # "core::events::click" — Core click event
62
+ #
63
+ # The settings field must be a JSON-encoded string matching the schema
64
+ # expected by the delegate. For Core custom code:
65
+ # settings: JSON.generate({ source: "console.log('hi');", language: "javascript" })
66
+ #
67
+ # @param property_id [String] Adobe property ID
68
+ # @param rule_id [String] Adobe rule ID to attach the component to
69
+ # @param name [String] Display name
70
+ # @param delegate_descriptor_id [String] Extension delegate identifier
71
+ # @param settings [String] JSON-encoded settings string
72
+ # @param extension_id [String] Adobe extension ID providing the delegate
73
+ # @param rule_order [Float] Execution order within the rule (default: 50.0)
74
+ # @param order [Integer] Order within same-type components (default: 0)
75
+ # @return [ReactorSDK::Resources::RuleComponent]
76
+ # @raise [ReactorSDK::UnprocessableEntityError] if attributes are invalid
77
+ #
78
+ def create(
79
+ property_id:,
80
+ rule_id:,
81
+ name:,
82
+ delegate_descriptor_id:,
83
+ settings:,
84
+ extension_id:,
85
+ rule_order: 50.0,
86
+ order: 0
87
+ )
88
+ payload = build_rule_component_payload(
89
+ name, delegate_descriptor_id, settings,
90
+ extension_id, rule_id, rule_order, order
91
+ )
92
+ response = @connection.post(
93
+ "/properties/#{property_id}/rule_components",
94
+ payload
95
+ )
96
+ @parser.parse(response['data'], Resources::RuleComponent)
97
+ end
98
+
99
+ ##
100
+ # Updates an existing rule component.
101
+ #
102
+ # @param rule_component_id [String] Adobe rule component ID
103
+ # @param attributes [Hash] Fields to update
104
+ # @return [ReactorSDK::Resources::RuleComponent]
105
+ # @raise [ReactorSDK::ResourceNotFoundError] if the component does not exist
106
+ #
107
+ def update(rule_component_id, attributes)
108
+ payload = build_payload('rule_components', attributes, id: rule_component_id)
109
+ response = @connection.patch("/rule_components/#{rule_component_id}", payload)
110
+ @parser.parse(response['data'], Resources::RuleComponent)
111
+ end
112
+
113
+ ##
114
+ # Deletes a rule component permanently.
115
+ #
116
+ # @param rule_component_id [String] Adobe rule component ID
117
+ # @return [nil]
118
+ # @raise [ReactorSDK::ResourceNotFoundError] if the component does not exist
119
+ #
120
+ def delete(rule_component_id)
121
+ @connection.delete("/rule_components/#{rule_component_id}")
122
+ nil
123
+ end
124
+
125
+ ##
126
+ # Retrieves the extension that owns the rule component delegate.
127
+ #
128
+ # @param rule_component_id [String]
129
+ # @return [ReactorSDK::Resources::Extension]
130
+ #
131
+ def extension(rule_component_id)
132
+ fetch_resource("/rule_components/#{rule_component_id}/extension", Resources::Extension)
133
+ end
134
+
135
+ ##
136
+ # Retrieves the origin revision head for a rule component.
137
+ #
138
+ # @param rule_component_id [String]
139
+ # @return [ReactorSDK::Resources::RuleComponent]
140
+ #
141
+ def origin(rule_component_id)
142
+ fetch_resource("/rule_components/#{rule_component_id}/origin", Resources::RuleComponent)
143
+ end
144
+
145
+ ##
146
+ # Lists rules that currently utilize a rule component.
147
+ #
148
+ # @param rule_component_id [String]
149
+ # @return [Array<ReactorSDK::Resources::Rule>]
150
+ #
151
+ def rules(rule_component_id)
152
+ list_resources("/rule_components/#{rule_component_id}/rules", Resources::Rule)
153
+ end
154
+
155
+ ##
156
+ # Lists notes attached to a rule component.
157
+ #
158
+ # @param rule_component_id [String]
159
+ # @return [Array<ReactorSDK::Resources::Note>]
160
+ #
161
+ def list_notes(rule_component_id)
162
+ list_notes_for_path("/rule_components/#{rule_component_id}/notes")
163
+ end
164
+
165
+ ##
166
+ # Creates a note on a rule component.
167
+ #
168
+ # @param rule_component_id [String]
169
+ # @param text [String]
170
+ # @return [ReactorSDK::Resources::Note]
171
+ #
172
+ def create_note(rule_component_id, text)
173
+ create_note_for_path("/rule_components/#{rule_component_id}/notes", text)
174
+ end
175
+
176
+ private
177
+
178
+ ##
179
+ # Builds the JSON:API payload for rule component creation.
180
+ # Includes both extension and rules relationships.
181
+ #
182
+ # @param name [String] Display name
183
+ # @param delegate_descriptor_id [String] Delegate identifier
184
+ # @param settings [String] JSON-encoded settings
185
+ # @param extension_id [String] Extension providing the delegate
186
+ # @param rule_id [String] Rule to attach this component to
187
+ # @param rule_order [Float] Rule execution order
188
+ # @param order [Integer] Component order within type
189
+ # @return [Hash] JSON:API compliant payload
190
+ #
191
+ def build_rule_component_payload(
192
+ name, delegate_descriptor_id, settings,
193
+ extension_id, rule_id, rule_order, order
194
+ )
195
+ {
196
+ data: {
197
+ type: 'rule_components',
198
+ attributes: {
199
+ name: name,
200
+ delegate_descriptor_id: delegate_descriptor_id,
201
+ settings: settings,
202
+ rule_order: rule_order,
203
+ order: order
204
+ },
205
+ relationships: {
206
+ extension: {
207
+ data: { id: extension_id, type: 'extensions' }
208
+ },
209
+ rules: {
210
+ data: [{ id: rule_id, type: 'rules' }]
211
+ }
212
+ }
213
+ }
214
+ }
215
+ end
216
+ end
217
+ end
218
+ end