overturo 0.7.2

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 (55) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +201 -0
  3. data/README.md +395 -0
  4. data/lib/overturo/api_operations/create.rb +14 -0
  5. data/lib/overturo/api_operations/delete.rb +14 -0
  6. data/lib/overturo/api_operations/list.rb +14 -0
  7. data/lib/overturo/api_operations/nested_resource.rb +52 -0
  8. data/lib/overturo/api_operations/retrieve.rb +14 -0
  9. data/lib/overturo/api_operations/update.rb +14 -0
  10. data/lib/overturo/api_resource.rb +107 -0
  11. data/lib/overturo/client.rb +231 -0
  12. data/lib/overturo/configuration.rb +24 -0
  13. data/lib/overturo/endpoints.rb +27 -0
  14. data/lib/overturo/errors.rb +120 -0
  15. data/lib/overturo/http_client.rb +166 -0
  16. data/lib/overturo/list_object.rb +73 -0
  17. data/lib/overturo/overturo_object.rb +87 -0
  18. data/lib/overturo/resources/agree/agreements.rb +20 -0
  19. data/lib/overturo/resources/agree/collaborations.rb +20 -0
  20. data/lib/overturo/resources/agree/quorum_requests.rb +22 -0
  21. data/lib/overturo/resources/comply/anchors.rb +25 -0
  22. data/lib/overturo/resources/comply/clean_rooms.rb +46 -0
  23. data/lib/overturo/resources/comply/evidence_packages.rb +15 -0
  24. data/lib/overturo/resources/comply/residency_posture.rb +31 -0
  25. data/lib/overturo/resources/comply/transfer_register.rb +28 -0
  26. data/lib/overturo/resources/connect/applications.rb +20 -0
  27. data/lib/overturo/resources/connect/connections.rb +20 -0
  28. data/lib/overturo/resources/connect/flows.rb +77 -0
  29. data/lib/overturo/resources/connect/meeting_consents.rb +60 -0
  30. data/lib/overturo/resources/connect/portability.rb +45 -0
  31. data/lib/overturo/resources/connect/webhooks.rb +42 -0
  32. data/lib/overturo/resources/consent/consent_records.rb +57 -0
  33. data/lib/overturo/resources/consent/consent_sessions.rb +49 -0
  34. data/lib/overturo/resources/consent/decisions.rb +54 -0
  35. data/lib/overturo/resources/consent/entitlements.rb +18 -0
  36. data/lib/overturo/resources/consent/trust_levels.rb +18 -0
  37. data/lib/overturo/resources/core/accounts.rb +18 -0
  38. data/lib/overturo/resources/core/me.rb +20 -0
  39. data/lib/overturo/resources/delegate/agent_identities.rb +23 -0
  40. data/lib/overturo/resources/delegate/authorization_receipts.rb +38 -0
  41. data/lib/overturo/resources/delegate/delegations.rb +34 -0
  42. data/lib/overturo/resources/delegate/disclosure_receipts.rb +24 -0
  43. data/lib/overturo/resources/delegate/security_event_streams.rb +22 -0
  44. data/lib/overturo/resources/protect/data_licenses.rb +19 -0
  45. data/lib/overturo/resources/protect/data_requests.rb +17 -0
  46. data/lib/overturo/resources/protect/policies.rb +23 -0
  47. data/lib/overturo/resources/protect/transfers.rb +19 -0
  48. data/lib/overturo/resources/verify/credentials.rb +23 -0
  49. data/lib/overturo/resources/verify/presentations.rb +18 -0
  50. data/lib/overturo/resources/verify/trust_scores.rb +17 -0
  51. data/lib/overturo/resources/verify/verification_sessions.rb +16 -0
  52. data/lib/overturo/resources/verify/vouches.rb +29 -0
  53. data/lib/overturo/version.rb +5 -0
  54. data/lib/overturo.rb +85 -0
  55. metadata +99 -0
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "uri"
5
+ require "json"
6
+ require "securerandom"
7
+
8
+ module Overturo
9
+ class HttpClient
10
+ RETRY_SLEEP_BASE = 0.5
11
+
12
+ attr_reader :last_request_id
13
+
14
+ def initialize(config)
15
+ @config = config
16
+ end
17
+
18
+ def get(path, params: {}, headers: {})
19
+ request(:get, path, params: params, extra_request_headers: headers)
20
+ end
21
+
22
+ def post(path, body: {}, idempotency_key: nil)
23
+ request(:post, path, body: body, idempotency_key: idempotency_key)
24
+ end
25
+
26
+ def patch(path, body: {}, idempotency_key: nil)
27
+ request(:patch, path, body: body, idempotency_key: idempotency_key)
28
+ end
29
+
30
+ def delete(path)
31
+ request(:delete, path)
32
+ end
33
+
34
+ private
35
+
36
+ def request(method, path, params: {}, body: nil, idempotency_key: nil, extra_request_headers: {})
37
+ uri = build_uri(path, params)
38
+ request_id = generate_request_id
39
+ retries = 0
40
+
41
+ begin
42
+ response = execute_request(method, uri, body, request_id: request_id, idempotency_key: idempotency_key,
43
+ extra_request_headers: extra_request_headers)
44
+ handle_response(response)
45
+ rescue RateLimitError, ApiError, ConnectionError, TimeoutError => e
46
+ if retries < @config.max_retries && retryable?(e)
47
+ retries += 1
48
+ sleep_time = RETRY_SLEEP_BASE * (2**(retries - 1))
49
+ log(:warn, "Retrying request #{request_id} (attempt #{retries}/#{@config.max_retries}) after #{sleep_time}s")
50
+ sleep(sleep_time)
51
+ retry
52
+ end
53
+ raise
54
+ end
55
+ end
56
+
57
+ def execute_request(method, uri, body, request_id: nil, idempotency_key: nil, extra_request_headers: {})
58
+ http = Net::HTTP.new(uri.host, uri.port)
59
+ http.use_ssl = uri.scheme == "https"
60
+ http.open_timeout = @config.open_timeout
61
+ http.read_timeout = @config.read_timeout
62
+ http.write_timeout = @config.write_timeout
63
+
64
+ req = build_request(method, uri, body, request_id: request_id, idempotency_key: idempotency_key,
65
+ extra_request_headers: extra_request_headers)
66
+ log(:debug, "[#{request_id}] #{method.upcase} #{uri.path}")
67
+ http.request(req)
68
+ rescue ::Timeout::Error, Errno::ETIMEDOUT => e
69
+ raise Overturo::TimeoutError, "Request timed out: #{e.message}"
70
+ rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::EHOSTUNREACH,
71
+ Errno::ENETUNREACH, SocketError, EOFError => e
72
+ raise Overturo::ConnectionError, "Connection failed: #{e.message}"
73
+ end
74
+
75
+ def build_request(method, uri, body, request_id: nil, idempotency_key: nil, extra_request_headers: {})
76
+ klass = {
77
+ get: Net::HTTP::Get,
78
+ post: Net::HTTP::Post,
79
+ patch: Net::HTTP::Patch,
80
+ delete: Net::HTTP::Delete
81
+ }.fetch(method)
82
+
83
+ extra_headers = {}
84
+ extra_headers["X-Request-ID"] = request_id if request_id
85
+ extra_headers["Idempotency-Key"] = idempotency_key if idempotency_key
86
+ # 189 — caller-supplied per-request headers (e.g. the discovery resource's
87
+ # X-Publishable-Key). Merged last so an explicit header wins.
88
+ extra_headers.merge!(extra_request_headers) if extra_request_headers && !extra_request_headers.empty?
89
+
90
+ req = klass.new(uri.request_uri, headers.merge(extra_headers))
91
+ req.body = JSON.generate(body) if body && !body.empty?
92
+ req
93
+ end
94
+
95
+ def build_uri(path, params)
96
+ # chomp a trailing slash so a base_url like "https://x.com/" doesn't produce
97
+ # "https://x.com//api/..." (some gateways 404 the double slash).
98
+ url = "#{@config.base_url.to_s.chomp("/")}/api/#{@config.api_version}#{path}"
99
+ uri = URI.parse(url)
100
+ uri.query = URI.encode_www_form(params) if params && !params.empty?
101
+ uri
102
+ end
103
+
104
+ def headers
105
+ {
106
+ "Authorization" => "Bearer #{@config.api_key}",
107
+ "Content-Type" => "application/json",
108
+ "Accept" => "application/json",
109
+ "User-Agent" => "overturo-ruby/#{Overturo::VERSION}"
110
+ }
111
+ end
112
+
113
+ def handle_response(response)
114
+ @last_response_request_id = response["X-Request-ID"]
115
+ status = response.code.to_i
116
+ body = response.body
117
+ json = parse_json(body)
118
+
119
+ return json || {} if status >= 200 && status < 300
120
+
121
+ message = error_message(json, body)
122
+ error_class = ERROR_MAP[status] || (status >= 500 ? ApiError : Error)
123
+
124
+ raise error_class.new(
125
+ message.to_s,
126
+ http_status: status,
127
+ http_body: body,
128
+ json_body: json
129
+ )
130
+ end
131
+
132
+ # `{error: {code, message}}` reads as "code: message"; a string error or a
133
+ # non-JSON body is passed through.
134
+ def error_message(json, body)
135
+ return body unless json.is_a?(Hash)
136
+
137
+ error = json["error"]
138
+ return [error["code"], error["message"]].compact.join(": ") if error.is_a?(Hash)
139
+
140
+ error || body
141
+ end
142
+
143
+ def parse_json(body)
144
+ return nil if body.nil? || body.empty?
145
+
146
+ JSON.parse(body)
147
+ rescue JSON::ParserError
148
+ nil
149
+ end
150
+
151
+ def retryable?(error)
152
+ error.is_a?(RateLimitError) || error.is_a?(ApiError) ||
153
+ error.is_a?(ConnectionError) || error.is_a?(TimeoutError)
154
+ end
155
+
156
+ def generate_request_id
157
+ @last_request_id = "req_#{SecureRandom.hex(12)}"
158
+ end
159
+
160
+ def log(level, message)
161
+ return unless @config.logger
162
+
163
+ @config.logger.send(level, "[Overturo] #{message}")
164
+ end
165
+ end
166
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ class ListObject
5
+ include Enumerable
6
+
7
+ attr_reader :data, :pagination
8
+
9
+ def initialize(data:, pagination:, http_client: nil, resource_path: nil, list_key: nil, params: {})
10
+ @data = data
11
+ @pagination = pagination
12
+ @http_client = http_client
13
+ @resource_path = resource_path
14
+ @list_key = list_key
15
+ @params = params
16
+ end
17
+
18
+ def each(&)
19
+ @data.each(&)
20
+ end
21
+
22
+ def more?
23
+ return false unless pagination
24
+
25
+ page_value(:page, 1) * page_value(:per_page, 25) < page_value(:total, 0)
26
+ end
27
+
28
+ alias has_more? more?
29
+
30
+ def auto_paging_each(&block)
31
+ return enum_for(:auto_paging_each) unless block_given?
32
+
33
+ @data.each(&block)
34
+ return unless @http_client && @resource_path && @list_key
35
+
36
+ current_params = @params.dup
37
+ current_page = page_value(:page, 1)
38
+
39
+ while pages_remaining?(current_page)
40
+ current_page += 1
41
+ current_params[:page] = current_page
42
+ response = @http_client.get(@resource_path, params: current_params)
43
+ items = response[@list_key] || []
44
+ items.each do |item|
45
+ block.call(item.is_a?(OverturoObject) ? item : OverturoObject.new(item))
46
+ end
47
+ @pagination = response["pagination"] || {}
48
+ end
49
+ end
50
+
51
+ def empty?
52
+ @data.empty?
53
+ end
54
+
55
+ def size
56
+ @data.size
57
+ end
58
+
59
+ alias length size
60
+
61
+ private
62
+
63
+ def page_value(key, default)
64
+ return default unless pagination
65
+
66
+ pagination[key.to_s] || pagination[key.to_sym] || default
67
+ end
68
+
69
+ def pages_remaining?(current_page)
70
+ current_page * page_value(:per_page, 25) < page_value(:total, 0)
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ class OverturoObject
5
+ def initialize(data = {})
6
+ @data = {}
7
+ data.each { |k, v| @data[k.to_s] = wrap_value(v) }
8
+ end
9
+
10
+ def [](key)
11
+ @data[key.to_s]
12
+ end
13
+
14
+ def []=(key, value)
15
+ @data[key.to_s] = wrap_value(value)
16
+ end
17
+
18
+ def respond_to_missing?(method_name, include_private = false)
19
+ @data.key?(method_name.to_s) || super
20
+ end
21
+
22
+ def method_missing(method_name, *args)
23
+ key = method_name.to_s
24
+ if @data.key?(key)
25
+ @data[key]
26
+ else
27
+ super
28
+ end
29
+ end
30
+
31
+ def to_h
32
+ @data.transform_values { |v| unwrap_value(v) }
33
+ end
34
+
35
+ def to_json(*args)
36
+ to_h.to_json(*args)
37
+ end
38
+
39
+ def to_s
40
+ "#<#{self.class} #{@data.map { |k, v| "#{k}=#{v.inspect}" }.join(" ")}>"
41
+ end
42
+
43
+ def inspect
44
+ to_s
45
+ end
46
+
47
+ def key?(key)
48
+ @data.key?(key.to_s)
49
+ end
50
+
51
+ def keys
52
+ @data.keys
53
+ end
54
+
55
+ def values
56
+ @data.values
57
+ end
58
+
59
+ def each(&)
60
+ @data.each(&)
61
+ end
62
+
63
+ private
64
+
65
+ def wrap_value(value)
66
+ case value
67
+ when Hash
68
+ OverturoObject.new(value)
69
+ when Array
70
+ value.map { |v| wrap_value(v) }
71
+ else
72
+ value
73
+ end
74
+ end
75
+
76
+ def unwrap_value(value)
77
+ case value
78
+ when OverturoObject
79
+ value.to_h
80
+ when Array
81
+ value.map { |v| unwrap_value(v) }
82
+ else
83
+ value
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module Resources
5
+ module Agree
6
+ class Agreements < ApiResource
7
+ include ApiOperations::Retrieve
8
+ include ApiOperations::List
9
+
10
+ RESOURCE_PATH = "/agreements"
11
+ OBJECT_KEY = "agreement"
12
+ LIST_KEY = "agreements"
13
+
14
+ collection_action :propose, method: :post
15
+ custom_action :counter, method: :post
16
+ custom_action :accept, method: :post
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module Resources
5
+ module Agree
6
+ class Collaborations < ApiResource
7
+ include ApiOperations::Create
8
+ include ApiOperations::Retrieve
9
+ include ApiOperations::List
10
+
11
+ RESOURCE_PATH = "/collaborations"
12
+ OBJECT_KEY = "collaboration"
13
+ LIST_KEY = "collaborations"
14
+
15
+ custom_action :invite, method: :post, returns: :raw
16
+ custom_action :sign, method: :post
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module Resources
5
+ module Agree
6
+ # M-of-N quorum authorization on Agreement actions ("collective
7
+ # guardianship" per the Agree surface). Lives at /api/v1/quorum_requests;
8
+ # /api/v1/decisions is the separate decisions API.
9
+ class QuorumRequests < ApiResource
10
+ include ApiOperations::Create
11
+ include ApiOperations::Retrieve
12
+ include ApiOperations::List
13
+
14
+ RESOURCE_PATH = "/quorum_requests"
15
+ OBJECT_KEY = "quorum_request"
16
+ LIST_KEY = "quorum_requests"
17
+
18
+ custom_action :vote, method: :post
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module Resources
5
+ module Comply
6
+ class Anchors < ApiResource
7
+ include ApiOperations::Retrieve
8
+
9
+ RESOURCE_PATH = "/anchors"
10
+ # 193 D12 — endpoints built by explicit http_client calls below.
11
+ declare_endpoint :get, "<resource>/{id}/receipts"
12
+ OBJECT_KEY = "anchor"
13
+ LIST_KEY = "anchors"
14
+
15
+ custom_action :export, method: :get, returns: :raw
16
+
17
+ def receipts(id, params = {})
18
+ receipts_path = "#{resource_path}/#{id}/receipts"
19
+ response = http_client.get(receipts_path, params: params)
20
+ unwrap_list(response, path: receipts_path, key: "receipts", params: params)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module Resources
5
+ module Comply
6
+ class CleanRooms < ApiResource
7
+ include ApiOperations::Create
8
+ include ApiOperations::Retrieve
9
+ include ApiOperations::List
10
+ include ApiOperations::Delete
11
+
12
+ RESOURCE_PATH = "/clean_rooms"
13
+ # 193 D12 — endpoints built by explicit http_client calls below.
14
+ declare_endpoint :post, "<resource>/{id}/queries"
15
+ declare_endpoint :get, "<resource>/{id}/queries"
16
+ declare_endpoint :get, "<resource>/{id}/queries/{query_id}"
17
+ OBJECT_KEY = "clean_room"
18
+ LIST_KEY = "clean_rooms"
19
+
20
+ custom_action :approve, method: :post
21
+
22
+ # Compute-to-data. Run a query inside the
23
+ # clean room and read its result. The result carries its privacy
24
+ # parameters (`k_anonymity_met`, `noise_parameters`) and a first-class
25
+ # `suppressed` flag + `suppression_reason`: a full k-anonymity
26
+ # suppression is surfaced honestly, never returned as a silent empty.
27
+ def run_query(id, params = {})
28
+ path = "#{resource_path}/#{id}/queries"
29
+ OverturoObject.new(http_client.post(path, body: params))
30
+ end
31
+
32
+ # GET /clean_rooms/:id/queries — list prior compute-to-data queries.
33
+ def queries(id, params = {})
34
+ path = "#{resource_path}/#{id}/queries"
35
+ unwrap_list(http_client.get(path, params: params), path: path, key: "queries", params: params)
36
+ end
37
+
38
+ # GET /clean_rooms/:id/queries/:query_id — read a single query result.
39
+ def query(id, query_id, params = {})
40
+ path = "#{resource_path}/#{id}/queries/#{query_id}"
41
+ OverturoObject.new(http_client.get(path, params: params))
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module Resources
5
+ module Comply
6
+ class EvidencePackages < ApiResource
7
+ include ApiOperations::Retrieve
8
+
9
+ RESOURCE_PATH = "/evidence_packages"
10
+ OBJECT_KEY = "evidence_package"
11
+ LIST_KEY = "evidence_packages"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module Resources
5
+ module Comply
6
+ # Read your residency posture: a per-country map of
7
+ # where your subjects' data is stored, the disclosure ledger, and an
8
+ # assurance status. Export a signed Proof of Residency. Singleton (no id).
9
+ class ResidencyPosture < ApiResource
10
+ RESOURCE_PATH = "/residency_posture"
11
+ # 193 D12 — endpoints built by explicit http_client calls below.
12
+ declare_endpoint :get, "<resource>"
13
+ declare_endpoint :post, "<resource>/evidence_package"
14
+ OBJECT_KEY = "residency_posture"
15
+
16
+ # GET /residency_posture — the per-country posture + assurance status.
17
+ def get(params = {})
18
+ response = http_client.get(resource_path, params: params)
19
+ OverturoObject.new(response)
20
+ end
21
+
22
+ # POST /residency_posture/evidence_package — the signed, anchored Proof
23
+ # of Residency, on the same verifiable path as the transfer register.
24
+ def evidence_package(params = {})
25
+ response = http_client.post("#{resource_path}/evidence_package", body: params)
26
+ OverturoObject.new(response)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module Resources
5
+ module Comply
6
+ # Read the cross-border transfer register and export
7
+ # its signed, verifiable evidence package. Each entry carries the lawful
8
+ # basis it relied on, the adequacy verdict, and the country pair. Read and
9
+ # export only — the SDK never creates a transfer.
10
+ class TransferRegister < ApiResource
11
+ include ApiOperations::List
12
+
13
+ RESOURCE_PATH = "/transfer_register"
14
+ # 193 D12 — endpoints built by explicit http_client calls below.
15
+ declare_endpoint :post, "<resource>/evidence_package"
16
+ OBJECT_KEY = "transfer"
17
+ LIST_KEY = "transfers"
18
+
19
+ # POST /transfer_register/evidence_package — the signed, anchored,
20
+ # independently-verifiable evidence package of the register.
21
+ def evidence_package(params = {})
22
+ response = http_client.post("#{resource_path}/evidence_package", body: params)
23
+ OverturoObject.new(response)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module Resources
5
+ module Connect
6
+ # Only the `publish` and `unpublish` member actions exist at the top
7
+ # level. Creating an application happens via the dashboard; per-application
8
+ # configuration uses the nested `applications/:id/...` resources — see
9
+ # Connect::Webhooks and Connect::Flows.
10
+ class Applications < ApiResource
11
+ RESOURCE_PATH = "/applications"
12
+ OBJECT_KEY = "application"
13
+ LIST_KEY = "applications"
14
+
15
+ custom_action :publish, method: :post
16
+ custom_action :unpublish, method: :post
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module Resources
5
+ module Connect
6
+ class Connections < ApiResource
7
+ include ApiOperations::Retrieve
8
+ include ApiOperations::List
9
+ include ApiOperations::Delete
10
+
11
+ RESOURCE_PATH = "/connections"
12
+ OBJECT_KEY = "connection"
13
+ LIST_KEY = "connections"
14
+
15
+ custom_action :suspend, method: :post
16
+ custom_action :unsuspend, method: :post
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module Resources
5
+ module Connect
6
+ # Flows are nested under applications:
7
+ # /api/v1/applications/:application_id/flows[/:id][/<action>]
8
+ class Flows < ApiResource
9
+ include ApiOperations::NestedResource
10
+
11
+ RESOURCE_PATH = "/applications"
12
+ # 193 D12 — endpoints built by explicit http_client calls below.
13
+ declare_endpoint :post, "<resource>/{application_id}/flows/{id}/activate"
14
+ declare_endpoint :post, "<resource>/{application_id}/flows/{id}/deprecate"
15
+ declare_endpoint :post, "<resource>/{application_id}/flows/{id}/archive"
16
+ declare_endpoint :post, "<resource>/{application_id}/flows/{id}/resolve_preview"
17
+ OBJECT_KEY = "flow"
18
+ LIST_KEY = "flows"
19
+
20
+ nested_resource :flow,
21
+ path: "flows",
22
+ object_key: "flow",
23
+ list_key: "flows",
24
+ operations: %i[create retrieve list update delete]
25
+
26
+ # Public API aliases — take (application_id, ...) as first arg.
27
+ def create(application_id, params = {})
28
+ create_flow(application_id, params)
29
+ end
30
+
31
+ def retrieve(application_id, id)
32
+ retrieve_flow(application_id, id)
33
+ end
34
+
35
+ def list(application_id, params = {})
36
+ list_flows(application_id, params)
37
+ end
38
+
39
+ def update(application_id, id, params = {})
40
+ update_flow(application_id, id, params)
41
+ end
42
+
43
+ def delete(application_id, id)
44
+ delete_flow(application_id, id)
45
+ end
46
+
47
+ # Member actions on the nested resource. NestedResource doesn't have a
48
+ # `nested_custom_action` helper yet, so these are written explicitly.
49
+ def activate(application_id, id, params = {})
50
+ member_action(application_id, id, "activate", params)
51
+ end
52
+
53
+ def deprecate(application_id, id, params = {})
54
+ member_action(application_id, id, "deprecate", params)
55
+ end
56
+
57
+ def archive(application_id, id, params = {})
58
+ member_action(application_id, id, "archive", params)
59
+ end
60
+
61
+ def resolve_preview(application_id, id, params = {})
62
+ member_action(application_id, id, "resolve_preview", params)
63
+ end
64
+
65
+ private
66
+
67
+ def member_action(application_id, id, action, params)
68
+ response = http_client.post(
69
+ "#{RESOURCE_PATH}/#{application_id}/flows/#{id}/#{action}",
70
+ body: params
71
+ )
72
+ unwrap(response)
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end