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,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module ApiOperations
5
+ module NestedResource
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ # `list_key` names the JSON key the API wraps the collection in; the
12
+ # generated method is always `list_<plural name>` (`list_method` overrides).
13
+ def nested_resource(name, path:, object_key: nil, list_key: nil, list_method: nil, operations: [])
14
+ { create: [:post, "<resource>/{parent_id}/#{path}"], retrieve: [:get, "<resource>/{parent_id}/#{path}/{id}"],
15
+ list: [:get, "<resource>/{parent_id}/#{path}"], update: [:patch, "<resource>/{parent_id}/#{path}/{id}"],
16
+ delete: [:delete, "<resource>/{parent_id}/#{path}/{id}"] }.each { |op, (m, t)| declare_endpoint(m, t) if operations.include?(op) }
17
+ operations.each do |op|
18
+ case op
19
+ when :create
20
+ define_method(:"create_#{name}") do |parent_id, params = {}|
21
+ response = http_client.post("#{resource_path}/#{parent_id}/#{path}", body: params)
22
+ unwrap(response, object_key || name.to_s)
23
+ end
24
+ when :retrieve
25
+ define_method(:"retrieve_#{name}") do |parent_id, id|
26
+ response = http_client.get("#{resource_path}/#{parent_id}/#{path}/#{id}")
27
+ unwrap(response, object_key || name.to_s)
28
+ end
29
+ when :list
30
+ define_method(:"list_#{list_method || "#{name}s"}") do |parent_id, params = {}|
31
+ lk = list_key || "#{name}s"
32
+ nested_path = "#{resource_path}/#{parent_id}/#{path}"
33
+ response = http_client.get(nested_path, params: params)
34
+ unwrap_list(response, path: nested_path, key: lk, params: params)
35
+ end
36
+ when :update
37
+ define_method(:"update_#{name}") do |parent_id, id, params = {}|
38
+ response = http_client.patch("#{resource_path}/#{parent_id}/#{path}/#{id}", body: params)
39
+ unwrap(response, object_key || name.to_s)
40
+ end
41
+ when :delete
42
+ define_method(:"delete_#{name}") do |parent_id, id|
43
+ response = http_client.delete("#{resource_path}/#{parent_id}/#{path}/#{id}")
44
+ unwrap(response, object_key || name.to_s)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module ApiOperations
5
+ module Retrieve
6
+ def self.included(base) = base.declare_endpoint(:get, "<resource>/{id}")
7
+
8
+ def retrieve(id)
9
+ response = http_client.get("#{resource_path}/#{id}")
10
+ unwrap(response)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ module ApiOperations
5
+ module Update
6
+ def self.included(base) = base.declare_endpoint(:patch, "<resource>/{id}")
7
+
8
+ def update(id, params = {})
9
+ response = http_client.patch("#{resource_path}/#{id}", body: params)
10
+ unwrap(response)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ class ApiResource
5
+ attr_reader :http_client
6
+
7
+ def initialize(http_client)
8
+ @http_client = http_client
9
+ end
10
+
11
+ def resource_path
12
+ self.class::RESOURCE_PATH
13
+ end
14
+
15
+ def object_key
16
+ self.class::OBJECT_KEY
17
+ end
18
+
19
+ def list_key
20
+ self.class::LIST_KEY
21
+ end
22
+
23
+ # Member-action transport: the verb the API declares for the action.
24
+ def member_request(method, path, params)
25
+ case method
26
+ when :post then http_client.post(path, body: params)
27
+ when :patch then http_client.patch(path, body: params)
28
+ else http_client.get(path, params: params)
29
+ end
30
+ end
31
+
32
+ def unwrap(response, key = object_key)
33
+ data = response.is_a?(Hash) && response.key?(key) ? response[key] : response
34
+ OverturoObject.new(data)
35
+ end
36
+
37
+ def unwrap_list(response, path: resource_path, key: list_key, params: {})
38
+ items = if response.is_a?(Array) then response # a bare collection (the accounts API renders one)
39
+ elsif response.is_a?(Hash) && response.key?(key) then response[key]
40
+ else
41
+ []
42
+ end
43
+ pagination = response.is_a?(Hash) ? (response["pagination"] || {}) : {}
44
+ wrapped = items.map { |item| OverturoObject.new(item) }
45
+
46
+ ListObject.new(
47
+ data: wrapped,
48
+ pagination: pagination,
49
+ http_client: http_client,
50
+ resource_path: path,
51
+ list_key: key,
52
+ params: params
53
+ )
54
+ end
55
+
56
+ class << self
57
+ # 193 D12 — every endpoint this class can construct, as [METHOD, template].
58
+ # Macros record templates with a <resource> token because `include
59
+ # ApiOperations::*` precedes RESOURCE_PATH in most classes; the token is
60
+ # expanded lazily here. Explicit http_client calls declare themselves.
61
+ def declare_endpoint(method, template)
62
+ (@declared_templates ||= []) << [method.to_s.upcase, template]
63
+ end
64
+
65
+ def declared_endpoints
66
+ (@declared_templates || []).map { |m, t| [m, t.sub("<resource>", self::RESOURCE_PATH)] }.uniq
67
+ end
68
+
69
+ def custom_action(name, method: :post, path: nil, returns: :object)
70
+ action_path = path || name.to_s
71
+ declare_endpoint(method, "<resource>/{id}/#{action_path}")
72
+
73
+ case returns
74
+ when :object
75
+ define_method(name) do |id, params = {}|
76
+ unwrap(member_request(method, "#{resource_path}/#{id}/#{action_path}", params))
77
+ end
78
+ when :raw
79
+ define_method(name) do |id, params = {}|
80
+ OverturoObject.new(member_request(method, "#{resource_path}/#{id}/#{action_path}", params))
81
+ end
82
+ when :list
83
+ raise ArgumentError, "custom_action #{name}: returns: :list is GET-only (declared #{method})" unless method == :get
84
+
85
+ define_method(name) do |id, params = {}|
86
+ lk = path || name.to_s
87
+ response = http_client.get("#{resource_path}/#{id}/#{lk}", params: params)
88
+ unwrap_list(response, path: "#{resource_path}/#{id}/#{lk}", key: lk, params: params)
89
+ end
90
+ end
91
+ end
92
+
93
+ def collection_action(name, method: :post, path: nil)
94
+ action_path = path || name.to_s
95
+ declare_endpoint(method, "<resource>/#{action_path}")
96
+ define_method(name) do |params = {}|
97
+ response = if method == :post
98
+ http_client.post("#{resource_path}/#{action_path}", body: params)
99
+ else
100
+ http_client.get("#{resource_path}/#{action_path}", params: params)
101
+ end
102
+ unwrap(response)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,231 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ class Client
5
+ attr_reader :config
6
+
7
+ def initialize(api_key: nil, base_url: nil, api_version: nil,
8
+ open_timeout: nil, read_timeout: nil, write_timeout: nil,
9
+ max_retries: nil, logger: nil)
10
+ @config = Configuration.new
11
+ @config.api_key = api_key if api_key
12
+ @config.base_url = base_url if base_url
13
+ @config.api_version = api_version if api_version
14
+ @config.open_timeout = open_timeout if open_timeout
15
+ @config.read_timeout = read_timeout if read_timeout
16
+ @config.write_timeout = write_timeout if write_timeout
17
+ @config.max_retries = max_retries if max_retries
18
+ @config.logger = logger if logger
19
+
20
+ @config.validate!
21
+ @http_client = HttpClient.new(@config)
22
+ end
23
+
24
+ def connect
25
+ @connect ||= ConnectSurface.new(@http_client)
26
+ end
27
+
28
+ def consent
29
+ @consent ||= ConsentSurface.new(@http_client)
30
+ end
31
+
32
+ def verify
33
+ @verify ||= VerifySurface.new(@http_client)
34
+ end
35
+
36
+ def protect
37
+ @protect ||= ProtectSurface.new(@http_client)
38
+ end
39
+
40
+ def agree
41
+ @agree ||= AgreeSurface.new(@http_client)
42
+ end
43
+
44
+ def delegate_ns
45
+ @delegate_ns ||= DelegateSurface.new(@http_client)
46
+ end
47
+
48
+ def comply
49
+ @comply ||= ComplySurface.new(@http_client)
50
+ end
51
+
52
+ def core
53
+ @core ||= CoreSurface.new(@http_client)
54
+ end
55
+ end
56
+
57
+ class SurfaceProxy
58
+ def initialize(http_client)
59
+ @http_client = http_client
60
+ @resources = {}
61
+ end
62
+
63
+ private
64
+
65
+ def resource(klass)
66
+ @resources[klass] ||= klass.new(@http_client)
67
+ end
68
+ end
69
+
70
+ class CoreSurface < SurfaceProxy
71
+ def me
72
+ resource(Resources::Core::Me)
73
+ end
74
+
75
+ def accounts
76
+ resource(Resources::Core::Accounts)
77
+ end
78
+ end
79
+
80
+ class ConnectSurface < SurfaceProxy
81
+ def applications
82
+ resource(Resources::Connect::Applications)
83
+ end
84
+
85
+ def webhooks
86
+ resource(Resources::Connect::Webhooks)
87
+ end
88
+
89
+ def connections
90
+ resource(Resources::Connect::Connections)
91
+ end
92
+
93
+ def flows
94
+ resource(Resources::Connect::Flows)
95
+ end
96
+
97
+ # Data portability (GDPR Art. 20).
98
+ def portability
99
+ resource(Resources::Connect::Portability)
100
+ end
101
+
102
+ # Meetings — the unit of record for meeting consent (window, platform,
103
+ # cancellation, participants with their decisions).
104
+ def meeting_consents
105
+ resource(Resources::Connect::MeetingConsents)
106
+ end
107
+ end
108
+
109
+ class ConsentSurface < SurfaceProxy
110
+ def consent_sessions
111
+ resource(Resources::Consent::ConsentSessions)
112
+ end
113
+
114
+ # 189 — pre-flight disclosure discovery (publishable-key-scoped).
115
+ def decisions
116
+ resource(Resources::Consent::Decisions)
117
+ end
118
+
119
+ # 201 — consent records captured outside Overturo's surfaces.
120
+ def consent_records
121
+ resource(Resources::Consent::ConsentRecords)
122
+ end
123
+
124
+ def entitlements
125
+ resource(Resources::Consent::Entitlements)
126
+ end
127
+
128
+ def trust_levels
129
+ resource(Resources::Consent::TrustLevels)
130
+ end
131
+ end
132
+
133
+ class VerifySurface < SurfaceProxy
134
+ def credentials
135
+ resource(Resources::Verify::Credentials)
136
+ end
137
+
138
+ def verification_sessions
139
+ resource(Resources::Verify::VerificationSessions)
140
+ end
141
+
142
+ def presentations
143
+ resource(Resources::Verify::Presentations)
144
+ end
145
+
146
+ def trust_scores
147
+ resource(Resources::Verify::TrustScores)
148
+ end
149
+
150
+ def vouches
151
+ resource(Resources::Verify::Vouches)
152
+ end
153
+ end
154
+
155
+ class ProtectSurface < SurfaceProxy
156
+ def policies
157
+ resource(Resources::Protect::Policies)
158
+ end
159
+
160
+ def data_requests
161
+ resource(Resources::Protect::DataRequests)
162
+ end
163
+
164
+ def transfers
165
+ resource(Resources::Protect::Transfers)
166
+ end
167
+
168
+ def data_licenses
169
+ resource(Resources::Protect::DataLicenses)
170
+ end
171
+ end
172
+
173
+ class AgreeSurface < SurfaceProxy
174
+ def agreements
175
+ resource(Resources::Agree::Agreements)
176
+ end
177
+
178
+ def quorum_requests
179
+ resource(Resources::Agree::QuorumRequests)
180
+ end
181
+
182
+ def collaborations
183
+ resource(Resources::Agree::Collaborations)
184
+ end
185
+ end
186
+
187
+ class DelegateSurface < SurfaceProxy
188
+ def delegations
189
+ resource(Resources::Delegate::Delegations)
190
+ end
191
+
192
+ def agent_identities
193
+ resource(Resources::Delegate::AgentIdentities)
194
+ end
195
+
196
+ def security_event_streams
197
+ resource(Resources::Delegate::SecurityEventStreams)
198
+ end
199
+
200
+ def authorization_receipts
201
+ resource(Resources::Delegate::AuthorizationReceipts)
202
+ end
203
+
204
+ def disclosure_receipts
205
+ resource(Resources::Delegate::DisclosureReceipts)
206
+ end
207
+ end
208
+
209
+ class ComplySurface < SurfaceProxy
210
+ def anchors
211
+ resource(Resources::Comply::Anchors)
212
+ end
213
+
214
+ def evidence_packages
215
+ resource(Resources::Comply::EvidencePackages)
216
+ end
217
+
218
+ def clean_rooms
219
+ resource(Resources::Comply::CleanRooms)
220
+ end
221
+
222
+ # Cross-border transfer register and residency posture.
223
+ def transfer_register
224
+ resource(Resources::Comply::TransferRegister)
225
+ end
226
+
227
+ def residency_posture
228
+ resource(Resources::Comply::ResidencyPosture)
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ class Configuration
5
+ attr_accessor :api_key, :base_url, :api_version,
6
+ :open_timeout, :read_timeout, :write_timeout,
7
+ :max_retries, :logger
8
+
9
+ def initialize
10
+ @api_key = nil
11
+ @base_url = "https://overturo.com"
12
+ @api_version = "v1"
13
+ @open_timeout = 30
14
+ @read_timeout = 80
15
+ @write_timeout = 30
16
+ @max_retries = 2
17
+ @logger = nil
18
+ end
19
+
20
+ def validate!
21
+ raise AuthenticationError, "No API key provided. Set your API key using Overturo::Client.new(api_key: \"sk_live_...\")" unless api_key && !api_key.empty?
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ # The machine-readable manifest of every endpoint this gem can call, derived
5
+ # from the resource classes' declared endpoints. `endpoints.json` at the gem
6
+ # root is the committed copy (rake endpoints:write); spec/overturo/endpoints_spec.rb
7
+ # keeps the two equal.
8
+ module Endpoints
9
+ def self.resource_classes
10
+ Overturo::Resources.constants.sort.flat_map do |surface|
11
+ mod = Overturo::Resources.const_get(surface)
12
+ mod.constants.sort.map { |c| mod.const_get(c) }.select { |k| k.is_a?(Class) && k < Overturo::ApiResource }
13
+ end
14
+ end
15
+
16
+ def self.manifest
17
+ entries = resource_classes.flat_map do |klass|
18
+ klass.declared_endpoints.map { |m, t| { "method" => m, "path" => "/api/v1#{t}", "resource" => klass.name } }
19
+ end
20
+ entries.uniq.sort_by { |e| [e["path"], e["method"]] }
21
+ end
22
+
23
+ def self.document
24
+ { "sdk" => "overturo-ruby", "endpoints" => manifest }
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,120 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overturo
4
+ class Error < StandardError
5
+ attr_reader :http_status, :http_body, :json_body
6
+
7
+ def initialize(message = nil, http_status: nil, http_body: nil, json_body: nil)
8
+ @http_status = http_status
9
+ @http_body = http_body
10
+ @json_body = json_body
11
+ super(message)
12
+ end
13
+
14
+ # Machine code from a structured error body, across both authority
15
+ # 422 shapes: the receipts read uses {"error" => "<code>",
16
+ # "reason" => <message>}, the disclosure mint uses {"error" =>
17
+ # <message>, "code" => "<code>"}. `code` wins when present; the two
18
+ # shapes are the server's contract, surfaced as-is.
19
+ # The API's error envelope is `{error: {code, message}}`; some endpoints
20
+ # still answer `{error: "<code or message>", code?: "<code>"}`.
21
+ def error_code
22
+ return nil unless json_body.is_a?(Hash)
23
+
24
+ error = json_body["error"]
25
+ return error["code"] if error.is_a?(Hash)
26
+
27
+ json_body["code"] || error
28
+ end
29
+ end
30
+
31
+ # 401
32
+ class AuthenticationError < Error; end
33
+ # 403
34
+ class ForbiddenError < Error; end
35
+ # 404
36
+ class NotFoundError < Error; end
37
+ # 400, 422
38
+ class InvalidRequestError < Error; end
39
+ # 429
40
+ class RateLimitError < Error; end
41
+ # 500+
42
+ class ApiError < Error; end
43
+ # Network errors
44
+ class ConnectionError < Error; end
45
+ # Timeout
46
+ class TimeoutError < Error; end
47
+
48
+ # @api private
49
+ ERROR_MAP = {
50
+ 400 => InvalidRequestError,
51
+ 401 => AuthenticationError,
52
+ 403 => ForbiddenError,
53
+ 404 => NotFoundError,
54
+ 422 => InvalidRequestError,
55
+ 429 => RateLimitError
56
+ }.freeze
57
+
58
+ # ── OAP denial classes ──────────────────────────────────────────────
59
+ # Raised by OAP-protocol failures (authorize, escalate, complete).
60
+ # Carry the structured envelope fields so callers can branch on
61
+ # `denial_category` or rescue the per-category subclass directly.
62
+ class OAPDenied < Error
63
+ attr_reader :reason_code, :failed_bound, :denial_category, :cascade_step, :detail
64
+
65
+ def initialize(message = nil, reason_code: nil, failed_bound: nil,
66
+ denial_category: nil, cascade_step: nil, detail: nil,
67
+ http_status: nil, http_body: nil, json_body: nil)
68
+ @reason_code = reason_code
69
+ @failed_bound = failed_bound
70
+ @denial_category = denial_category
71
+ @cascade_step = cascade_step
72
+ @detail = detail
73
+ super(message, http_status: http_status, http_body: http_body, json_body: json_body)
74
+ end
75
+
76
+ # Build the most-specific subclass for an OAP error envelope.
77
+ # Reason-code dispatch takes precedence over category dispatch so
78
+ # the most specific subclass wins (sequence denials are
79
+ # trajectory_denied but get their own subclass).
80
+ # @param envelope [Hash] the parsed JSON body (root, not the inner `error`)
81
+ # @param status [Integer, nil] HTTP status for transport-level matching
82
+ def self.from_envelope(envelope, status: nil)
83
+ err = (envelope || {})["error"] || {}
84
+ target = REASON_CODE_TO_CLASS[err["reason_code"]] ||
85
+ CATEGORY_TO_CLASS.fetch(err["denial_category"], OAPDenied)
86
+ target.new(
87
+ err["message"],
88
+ reason_code: err["reason_code"],
89
+ failed_bound: err["failed_bound"],
90
+ denial_category: err["denial_category"],
91
+ cascade_step: err["cascade_step"],
92
+ detail: err["detail"],
93
+ http_status: status,
94
+ json_body: envelope
95
+ )
96
+ end
97
+ end
98
+
99
+ # denial_category == "authorization_denied" — OAuth/DPoP layer failed.
100
+ class OAPAuthorizationDenied < OAPDenied; end
101
+ # denial_category == "intent_denied" — request outside grant bounds.
102
+ class OAPIntentDenied < OAPDenied; end
103
+ # denial_category == "trajectory_denied" — execution history blocked the action.
104
+ class OAPTrajectoryDenied < OAPDenied; end
105
+ # sequence_bounds violation
106
+ # (sequence_prohibited / sequence_missing_predecessor). A trajectory
107
+ # denial with a structural-ordering flavour.
108
+ class OAPSequenceDenied < OAPTrajectoryDenied; end
109
+
110
+ OAPDenied::CATEGORY_TO_CLASS = {
111
+ "authorization_denied" => OAPAuthorizationDenied,
112
+ "intent_denied" => OAPIntentDenied,
113
+ "trajectory_denied" => OAPTrajectoryDenied
114
+ }.freeze
115
+
116
+ OAPDenied::REASON_CODE_TO_CLASS = {
117
+ "sequence_prohibited" => OAPSequenceDenied,
118
+ "sequence_missing_predecessor" => OAPSequenceDenied
119
+ }.freeze
120
+ end