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
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0aa1ebc8313c5d522d17ac36860404dddb917ff6b92df673f1b6161b28a78523
4
+ data.tar.gz: 9ffc87d3a9413abfffdfd0b15b9e3a3d8b42721f7d80d0c2eaf481fec0ac93ee
5
+ SHA512:
6
+ metadata.gz: 67970e3f8a09bd53c7654fb71b104e76ca12318f0dec8745aa4a84a0c1f62217fdd4f91f199c0218f613ffe05a25153d91f885d9c1ebb21d5fd49ce2260142b8
7
+ data.tar.gz: 65a4ecb927896f6bddd075916ed172b1e1653446c87c41120524614303d975646cff5416725e5828543a7f310ddc64cfa39f1a2700d5928701dfbb8f273aa156
data/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ ## [0.1.0] - 2026-04-01
2
+
3
+ - Added support for app configurations, callbacks, secrets, extension packages,
4
+ extension package usage authorizations, profile lookup, search, and direct
5
+ note lookup to align the SDK with Adobe's current Reactor endpoint families.
6
+ - Added missing relationship and maintenance operations across properties,
7
+ extensions, libraries, builds, rules, rule components, and notes-bearing
8
+ resources.
9
+ - Corrected audit event listing to use Adobe's current global `/audit_events`
10
+ endpoint while keeping `list_for_property` as a backward-compatible wrapper.
11
+ - Added multipart extension package upload support and coverage for the new
12
+ endpoint surface.
13
+ - Added contributor and security documentation for open source maintenance.
14
+ - Added a pinned `.ruby-version` to align local development with CI.
15
+ - Expanded CI and core infrastructure test coverage.
16
+ - Aligned gem metadata and install documentation with the published gem name.
17
+ - Documented current Adobe Reactor API coverage and multi-client usage patterns.
18
+ - Added test coverage proving separate client instances keep credentials isolated.
19
+ - Initial public release.
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Dhairya Gabhawala
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,281 @@
1
+ <p align="center">
2
+ <img src=".github/assets/reactor-sdk-lockup.svg" alt="ReactorSDK" width="520">
3
+ </p>
4
+
5
+ <p align="center">
6
+ <a href="https://github.com/dhairyagabha/reactor_sdk/actions/workflows/main.yml">
7
+ <img src="https://github.com/dhairyagabha/reactor_sdk/actions/workflows/main.yml/badge.svg" alt="CI">
8
+ </a>
9
+ <a href="https://rubygems.org/gems/reactor_sdk">
10
+ <img src="https://img.shields.io/gem/v/reactor_sdk.svg" alt="RubyGems version">
11
+ </a>
12
+ </p>
13
+
14
+ <p align="center">
15
+ <a href="https://reactor-sdk.dhairyagabhawala.com">Documentation</a>
16
+ ·
17
+ <a href="https://github.com/dhairyagabha/reactor_sdk/blob/main/CHANGELOG.md">Changelog</a>
18
+ ·
19
+ <a href="https://rubygems.org/gems/reactor_sdk">RubyGems</a>
20
+ ·
21
+ <a href="https://github.com/dhairyagabha/reactor_sdk">GitHub</a>
22
+ </p>
23
+
24
+ # ReactorSDK
25
+
26
+ `reactor_sdk` is a Ruby SDK for the Adobe Launch / Data Collection Reactor API. It handles OAuth Server-to-Server authentication, JSON:API parsing, pagination, retries, rate limiting, revision snapshots, and review-friendly comparison helpers so application code can work with typed Ruby objects instead of raw HTTP payloads.
27
+
28
+ ## Features
29
+
30
+ - OAuth Server-to-Server authentication with automatic token refresh
31
+ - Typed resource objects across companies, properties, rules, data elements, extensions, libraries, builds, revisions, notes, and more
32
+ - Automatic pagination for list endpoints
33
+ - Consistent error classes and retry behavior around Adobe API failures
34
+ - Library-aware review helpers for rules, data elements, and extensions
35
+ - Upstream-chain lookup for resource review across Development, Staging, and Production
36
+ - Library-to-library comparison output with status, revision IDs, and normalized review payloads
37
+
38
+ ## Installation
39
+
40
+ Add the gem to your application:
41
+
42
+ ```ruby
43
+ gem "reactor_sdk"
44
+ ```
45
+
46
+ Then install it:
47
+
48
+ ```bash
49
+ bundle install
50
+ ```
51
+
52
+ Or install directly:
53
+
54
+ ```bash
55
+ gem install reactor_sdk
56
+ ```
57
+
58
+ ## Authentication and Configuration
59
+
60
+ ReactorSDK uses Adobe OAuth Server-to-Server credentials. JWT / Service Account credentials are not supported.
61
+
62
+ ```ruby
63
+ require "reactor_sdk"
64
+
65
+ client = ReactorSDK::Client.new(
66
+ client_id: ENV.fetch("ADOBE_CLIENT_ID"),
67
+ client_secret: ENV.fetch("ADOBE_CLIENT_SECRET"),
68
+ org_id: ENV.fetch("ADOBE_IMS_ORG_ID")
69
+ )
70
+ ```
71
+
72
+ Optional configuration is passed to the same client constructor:
73
+
74
+ ```ruby
75
+ client = ReactorSDK::Client.new(
76
+ client_id: "your-client-id",
77
+ client_secret: "your-client-secret",
78
+ org_id: "your-org-id@AdobeOrg",
79
+ base_url: "https://reactor.adobe.io",
80
+ ims_token_url: "https://ims-na1.adobelogin.com/ims/token/v3",
81
+ timeout: 30,
82
+ logger: Logger.new($stdout),
83
+ auto_refresh_token: true
84
+ )
85
+ ```
86
+
87
+ ## Quick Start
88
+
89
+ ```ruby
90
+ require "reactor_sdk"
91
+
92
+ client = ReactorSDK::Client.new(
93
+ client_id: ENV.fetch("ADOBE_CLIENT_ID"),
94
+ client_secret: ENV.fetch("ADOBE_CLIENT_SECRET"),
95
+ org_id: ENV.fetch("ADOBE_IMS_ORG_ID")
96
+ )
97
+
98
+ # List companies available to the credential set.
99
+ companies = client.companies.list
100
+ company = companies.first
101
+
102
+ # List properties inside the company.
103
+ properties = client.properties.list_for_company(company.id)
104
+ property = properties.first
105
+
106
+ # List rules in the property.
107
+ rules = client.rules.list_for_property(property.id)
108
+ puts rules.first&.name
109
+ ```
110
+
111
+ ## Review and Promotion Workflows
112
+
113
+ ReactorSDK includes higher-level helpers for review tooling and release workflows, not just CRUD wrappers.
114
+
115
+ ### Work with a Library Snapshot
116
+
117
+ ```ruby
118
+ # LB_DEV = development library ID.
119
+ # PR123 = property ID.
120
+ snapshot = client.libraries.find_snapshot("LB_DEV", property_id: "PR123")
121
+
122
+ # Point-in-time rule components associated with the rule inside this library snapshot.
123
+ snapshot.rule_components_for_rule("RL123").map(&:id)
124
+
125
+ # Snapshot-scoped impact analysis for a data element.
126
+ snapshot.impacted_rules_for("DE123").map(&:name)
127
+ ```
128
+
129
+ ### Build Comprehensive Review Objects
130
+
131
+ ```ruby
132
+ rule_review = client.rules.find_comprehensive(
133
+ "RL123",
134
+ library_id: "LB_DEV",
135
+ property_id: "PR123"
136
+ )
137
+
138
+ data_element_review = client.data_elements.find_comprehensive(
139
+ "DE123",
140
+ library_id: "LB_DEV",
141
+ property_id: "PR123"
142
+ )
143
+
144
+ extension_review = client.extensions.find_comprehensive(
145
+ "EX123",
146
+ library_id: "LB_DEV",
147
+ property_id: "PR123"
148
+ )
149
+
150
+ puts rule_review.normalized_json
151
+ puts data_element_review.normalized_json
152
+ puts extension_review.normalized_json
153
+ ```
154
+
155
+ These comprehensive review objects include the resource plus the associated records a reviewer usually needs:
156
+
157
+ - Rules include rule components
158
+ - Data elements include referenced data elements and impacted rules
159
+ - Extensions include dependent data elements, rule components, and rules
160
+
161
+ ### Resolve Upstream Versions
162
+
163
+ ```ruby
164
+ chain = client.rules.comprehensive_upstream_chain(
165
+ "RL123",
166
+ library_id: "LB_DEV",
167
+ property_id: "PR123"
168
+ )
169
+
170
+ staging_entry = chain.entries.find { |entry| entry.stage == "staging" }
171
+
172
+ puts chain.target_revision_id
173
+ puts staging_entry&.revision_id
174
+ puts staging_entry&.normalized_json
175
+ ```
176
+
177
+ ### Compare Two Libraries
178
+
179
+ ```ruby
180
+ # Compare Development against Staging.
181
+ comparison = client.libraries.compare(
182
+ "LB_DEV",
183
+ baseline_library_id: "LB_STG",
184
+ property_id: "PR123"
185
+ )
186
+
187
+ comparison.entries.each do |entry|
188
+ puts "#{entry.resource_type} #{entry.resource_id} #{entry.status}"
189
+ puts entry.current_revision_id
190
+ puts entry.baseline_revision_id
191
+ end
192
+
193
+ # Inspect normalized output for one entry.
194
+ entry = comparison.entries.first
195
+ puts entry.current_normalized_json
196
+ puts entry.baseline_normalized_json
197
+ ```
198
+
199
+ Sample comparison output:
200
+
201
+ ```ruby
202
+ # Example status rows you might print from comparison.entries:
203
+ # rules RL100 modified
204
+ # current revision = RE_CUR_RULE
205
+ # baseline revision = RE_BASE_RULE
206
+ #
207
+ # rules RL200 added
208
+ # current revision = RE_ADDED
209
+ # baseline revision = nil
210
+ #
211
+ # data_elements DE200 removed
212
+ # current revision = nil
213
+ # baseline revision = RE_REMOVED
214
+ #
215
+ # extensions EX100 unchanged
216
+ # current revision = RE_EX
217
+ # baseline revision = RE_EX
218
+ ```
219
+
220
+ Comparison is performed across the library's top-level rules, data elements, and extensions. Rule components are still included in the comprehensive rule payload so rule diffs remain readable.
221
+
222
+ ## Endpoint Coverage
223
+
224
+ The SDK currently exposes these endpoint families:
225
+
226
+ - Companies
227
+ - Properties
228
+ - App configurations
229
+ - Callbacks
230
+ - Secrets
231
+ - Environments
232
+ - Hosts
233
+ - Rules
234
+ - Rule components
235
+ - Data elements
236
+ - Extensions
237
+ - Extension packages
238
+ - Extension package usage authorizations
239
+ - Libraries
240
+ - Builds
241
+ - Revisions
242
+ - Notes
243
+ - Audit events
244
+ - Profiles
245
+ - Search
246
+
247
+ ## Documentation
248
+
249
+ Full guides, API reference pages, example payloads, and review-workflow documentation are available at:
250
+
251
+ - https://reactor-sdk.dhairyagabhawala.com
252
+
253
+ ## Development
254
+
255
+ Install dependencies:
256
+
257
+ ```bash
258
+ bundle install
259
+ ```
260
+
261
+ Run the test suite:
262
+
263
+ ```bash
264
+ bundle exec rspec
265
+ ```
266
+
267
+ Run RuboCop:
268
+
269
+ ```bash
270
+ bundle exec rubocop
271
+ ```
272
+
273
+ Build the gem:
274
+
275
+ ```bash
276
+ gem build reactor_sdk.gemspec
277
+ ```
278
+
279
+ ## Contributing
280
+
281
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for contribution and development guidance.
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file authentication.rb
5
+ # @description Handles Adobe IMS OAuth Server-to-Server authentication.
6
+ #
7
+ # Fetches and caches access tokens using the client_credentials grant.
8
+ # Tokens are refreshed automatically when within REFRESH_BUFFER_SECONDS
9
+ # of expiry. Thread-safe via Mutex.
10
+ #
11
+ # Adobe deprecated JWT (Service Account) authentication on January 1 2025.
12
+ # This implementation uses OAuth Server-to-Server only.
13
+ #
14
+ # The token URL is read from config rather than hardcoded so that tests
15
+ # can override it via Configuration's ims_token_url parameter without
16
+ # any monkey-patching or global state changes.
17
+ #
18
+ # @domain Infrastructure
19
+ # @depends ReactorSDK::Configuration
20
+ #
21
+ # @see https://developer.adobe.com/developer-console/docs/guides/authentication/ServerToServerAuthentication/
22
+ #
23
+
24
+ module ReactorSDK
25
+ class Authentication
26
+ # Adobe IMS token endpoint — single global endpoint for all regions
27
+ # Read by Configuration as its default value for ims_token_url
28
+ IMS_TOKEN_URL = 'https://ims-na1.adobelogin.com/ims/token/v3'
29
+
30
+ # Refresh the token this many seconds before actual expiry.
31
+ # Prevents edge cases where a token expires between check and use.
32
+ REFRESH_BUFFER_SECONDS = 300
33
+
34
+ # Required OAuth scopes for full Reactor API access
35
+ REACTOR_SCOPE = [
36
+ 'openid',
37
+ 'AdobeID',
38
+ 'read_organizations',
39
+ 'additional_info.projectedProductContext'
40
+ ].join(',').freeze
41
+
42
+ ##
43
+ # @param config [ReactorSDK::Configuration] SDK configuration instance
44
+ #
45
+ def initialize(config)
46
+ @config = config
47
+ @token = nil
48
+ @token_expiry = nil
49
+ @mutex = Mutex.new
50
+ end
51
+
52
+ ##
53
+ # Returns a valid access token, fetching or refreshing if necessary.
54
+ # Thread-safe — uses a Mutex to prevent parallel token fetches in
55
+ # multi-threaded environments such as Puma.
56
+ #
57
+ # @return [String] Valid Adobe IMS Bearer access token
58
+ # @raise [ReactorSDK::AuthenticationError] if the token request fails
59
+ #
60
+ def access_token
61
+ @mutex.synchronize do
62
+ fetch_token if token_expired?
63
+ @token
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ ##
70
+ # Returns true if the token is missing or within the refresh buffer window.
71
+ #
72
+ # @return [Boolean]
73
+ #
74
+ def token_expired?
75
+ @token.nil? ||
76
+ Time.now.utc >= (@token_expiry - REFRESH_BUFFER_SECONDS)
77
+ end
78
+
79
+ ##
80
+ # Fetches a fresh access token from Adobe IMS using client_credentials grant.
81
+ # Uses @config.ims_token_url so tests can intercept without hitting Adobe.
82
+ #
83
+ # @raise [ReactorSDK::AuthenticationError] if the IMS request fails
84
+ # @sideeffect Sets @token and @token_expiry
85
+ #
86
+ def fetch_token
87
+ response = Faraday.post(@config.ims_token_url, token_request_params)
88
+
89
+ unless response.success?
90
+ raise AuthenticationError.new(
91
+ "Adobe IMS token request failed (HTTP #{response.status}). " \
92
+ 'Check your client_id and client_secret.',
93
+ status: response.status
94
+ )
95
+ end
96
+
97
+ parse_token_response(response.body)
98
+ rescue Faraday::Error => e
99
+ raise AuthenticationError.new(
100
+ "Network error during token fetch: #{e.message}",
101
+ cause: e
102
+ )
103
+ end
104
+
105
+ ##
106
+ # Builds the POST body parameters for the IMS token request.
107
+ #
108
+ # @return [Hash] Form-encoded parameters for the IMS endpoint
109
+ #
110
+ def token_request_params
111
+ {
112
+ grant_type: 'client_credentials',
113
+ client_id: @config.client_id,
114
+ client_secret: @config.client_secret,
115
+ scope: REACTOR_SCOPE
116
+ }
117
+ end
118
+
119
+ ##
120
+ # Parses the JSON response and stores the token and its expiry time.
121
+ #
122
+ # @param body [String] Raw JSON response body from Adobe IMS
123
+ # @raise [ReactorSDK::AuthenticationError] if body is not valid JSON
124
+ # @sideeffect Sets @token and @token_expiry
125
+ #
126
+ def parse_token_response(body)
127
+ data = JSON.parse(body)
128
+ @token = data.fetch('access_token')
129
+ @token_expiry = Time.now.utc + data.fetch('expires_in').to_i
130
+ rescue JSON::ParserError, KeyError => e
131
+ raise AuthenticationError.new(
132
+ 'Could not parse Adobe IMS token response',
133
+ cause: e
134
+ )
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,186 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @file client.rb
5
+ # @description Main entry point for the ReactorSDK gem.
6
+ #
7
+ # Instantiate one client per Adobe org. The client wires together all
8
+ # infrastructure and exposes every endpoint group as a named method.
9
+ #
10
+ # @example Basic usage
11
+ # client = ReactorSDK::Client.new(
12
+ # client_id: ENV["ADOBE_CLIENT_ID"],
13
+ # client_secret: ENV["ADOBE_CLIENT_SECRET"],
14
+ # org_id: ENV["ADOBE_IMS_ORG_ID"]
15
+ # )
16
+ #
17
+ # # Fetch hosts before creating an environment
18
+ # hosts = client.hosts.list_for_property("PR123")
19
+ # client.environments.create(
20
+ # property_id: "PR123",
21
+ # name: "jsmith-dev",
22
+ # stage: "development",
23
+ # host_id: hosts.first.id
24
+ # )
25
+ #
26
+
27
+ module ReactorSDK
28
+ class Client
29
+ ENDPOINT_CLASSES = {
30
+ companies: Endpoints::Companies,
31
+ properties: Endpoints::Properties,
32
+ app_configurations: Endpoints::AppConfigurations,
33
+ callbacks: Endpoints::Callbacks,
34
+ secrets: Endpoints::Secrets,
35
+ environments: Endpoints::Environments,
36
+ hosts: Endpoints::Hosts,
37
+ rules: Endpoints::Rules,
38
+ rule_components: Endpoints::RuleComponents,
39
+ data_elements: Endpoints::DataElements,
40
+ extensions: Endpoints::Extensions,
41
+ extension_packages: Endpoints::ExtensionPackages,
42
+ extension_package_usage_authorizations: Endpoints::ExtensionPackageUsageAuthorizations,
43
+ libraries: Endpoints::Libraries,
44
+ builds: Endpoints::Builds,
45
+ audit_events: Endpoints::AuditEvents,
46
+ revisions: Endpoints::Revisions,
47
+ profiles: Endpoints::Profiles,
48
+ search: Endpoints::Search,
49
+ notes: Endpoints::Notes
50
+ }.freeze
51
+
52
+ # @return [ReactorSDK::Endpoints::Companies]
53
+ attr_reader :companies
54
+
55
+ # @return [ReactorSDK::Endpoints::Properties]
56
+ attr_reader :properties
57
+
58
+ # @return [ReactorSDK::Endpoints::AppConfigurations]
59
+ attr_reader :app_configurations
60
+
61
+ # @return [ReactorSDK::Endpoints::Callbacks]
62
+ attr_reader :callbacks
63
+
64
+ # @return [ReactorSDK::Endpoints::Secrets]
65
+ attr_reader :secrets
66
+
67
+ # @return [ReactorSDK::Endpoints::Environments]
68
+ attr_reader :environments
69
+
70
+ # @return [ReactorSDK::Endpoints::Hosts]
71
+ attr_reader :hosts
72
+
73
+ # @return [ReactorSDK::Endpoints::Rules]
74
+ attr_reader :rules
75
+
76
+ # @return [ReactorSDK::Endpoints::RuleComponents]
77
+ attr_reader :rule_components
78
+
79
+ # @return [ReactorSDK::Endpoints::DataElements]
80
+ attr_reader :data_elements
81
+
82
+ # @return [ReactorSDK::Endpoints::Extensions]
83
+ attr_reader :extensions
84
+
85
+ # @return [ReactorSDK::Endpoints::ExtensionPackages]
86
+ attr_reader :extension_packages
87
+
88
+ # @return [ReactorSDK::Endpoints::ExtensionPackageUsageAuthorizations]
89
+ attr_reader :extension_package_usage_authorizations
90
+
91
+ # @return [ReactorSDK::Endpoints::Libraries]
92
+ attr_reader :libraries
93
+
94
+ # @return [ReactorSDK::Endpoints::Builds]
95
+ attr_reader :builds
96
+
97
+ # @return [ReactorSDK::Endpoints::AuditEvents]
98
+ attr_reader :audit_events
99
+
100
+ # @return [ReactorSDK::Endpoints::Revisions]
101
+ attr_reader :revisions
102
+
103
+ # @return [ReactorSDK::Endpoints::Profiles]
104
+ attr_reader :profiles
105
+
106
+ # @return [ReactorSDK::Endpoints::Search]
107
+ attr_reader :search
108
+
109
+ # @return [ReactorSDK::Endpoints::Notes]
110
+ attr_reader :notes
111
+
112
+ # @return [ReactorSDK::Configuration]
113
+ attr_reader :config
114
+
115
+ ##
116
+ # Initializes the client and all infrastructure dependencies.
117
+ #
118
+ # @param client_id [String] Adobe Developer Console client ID
119
+ # @param client_secret [String] Adobe Developer Console client secret
120
+ # @param org_id [String] Adobe IMS organisation ID
121
+ # @param base_url [String] Override Reactor API base URL (optional)
122
+ # @param ims_token_url [String] Override IMS token URL — for testing (optional)
123
+ # @param timeout [Integer] HTTP timeout in seconds (optional)
124
+ # @param logger [Logger] Custom logger (optional)
125
+ # @param auto_refresh_token [Boolean] Auto-refresh token before expiry (optional)
126
+ # @raise [ReactorSDK::ConfigurationError] if any required credential is blank
127
+ #
128
+ def initialize(
129
+ client_id:,
130
+ client_secret:,
131
+ org_id:,
132
+ base_url: Configuration::DEFAULT_BASE_URL,
133
+ ims_token_url: Authentication::IMS_TOKEN_URL,
134
+ timeout: Configuration::DEFAULT_TIMEOUT,
135
+ logger: nil,
136
+ auto_refresh_token: true
137
+ )
138
+ @config = Configuration.new(
139
+ client_id: client_id,
140
+ client_secret: client_secret,
141
+ org_id: org_id,
142
+ base_url: base_url,
143
+ ims_token_url: ims_token_url,
144
+ timeout: timeout,
145
+ logger: logger,
146
+ auto_refresh_token: auto_refresh_token
147
+ )
148
+
149
+ build_infrastructure
150
+ build_endpoints
151
+ end
152
+
153
+ private
154
+
155
+ ##
156
+ # Instantiates all infrastructure objects in dependency order.
157
+ #
158
+ # @sideeffect Sets @auth, @rate_limiter, @connection, @paginator, @parser
159
+ #
160
+ def build_infrastructure
161
+ @auth = Authentication.new(@config)
162
+ @rate_limiter = RateLimiter.new
163
+ @connection = Connection.new(@config, @auth, @rate_limiter)
164
+ @paginator = Paginator.new(@connection)
165
+ @parser = ResponseParser.new
166
+ end
167
+
168
+ ##
169
+ # Instantiates all endpoint group objects.
170
+ # Add new endpoint groups here as they are implemented.
171
+ #
172
+ # @sideeffect Sets all endpoint attr_reader values
173
+ #
174
+ def build_endpoints
175
+ deps = {
176
+ connection: @connection,
177
+ paginator: @paginator,
178
+ parser: @parser
179
+ }
180
+
181
+ ENDPOINT_CLASSES.each do |name, endpoint_class|
182
+ instance_variable_set(:"@#{name}", endpoint_class.new(**deps))
183
+ end
184
+ end
185
+ end
186
+ end