moov_ruby 0.0.0.pre.dev.23 → 0.0.0.pre.dev.24

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 (116) hide show
  1. checksums.yaml +4 -4
  2. data/lib/moov/avatars.rb +275 -0
  3. data/lib/moov/models/components/allowedscheduleerror.rb +36 -0
  4. data/lib/moov/models/components/allowedscheduleerror.rbi +15 -0
  5. data/lib/moov/models/components/avataruploadrequest.rb +32 -0
  6. data/lib/moov/models/components/avataruploadrequest.rbi +13 -0
  7. data/lib/moov/models/components/avataruploadrequest_file.rb +36 -0
  8. data/lib/moov/models/components/avataruploadrequest_file.rbi +15 -0
  9. data/lib/moov/models/components/capabilityid.rb +1 -0
  10. data/lib/moov/models/components/createtransfer.rb +6 -2
  11. data/lib/moov/models/components/createtransfer.rbi +2 -0
  12. data/lib/moov/models/components/feepaidby.rb +19 -0
  13. data/lib/moov/models/components/feepaidby.rbi +11 -0
  14. data/lib/moov/models/components/fullissuedcard.rb +3 -3
  15. data/lib/moov/models/components/incurredfee.rb +6 -2
  16. data/lib/moov/models/components/incurredfee.rbi +2 -0
  17. data/lib/moov/models/components/issuedcard.rb +3 -3
  18. data/lib/moov/models/components/issuedcontrols.rb +52 -0
  19. data/lib/moov/models/components/issuedcontrols.rbi +23 -0
  20. data/lib/moov/models/components/issuedcontrols_allowedschedule.rb +36 -0
  21. data/lib/moov/models/components/issuedcontrols_allowedschedule.rbi +15 -0
  22. data/lib/moov/models/components/issuedvelocitylimit.rb +60 -0
  23. data/lib/moov/models/components/issuedvelocitylimit.rbi +27 -0
  24. data/lib/moov/models/components/issuingcontrols.rb +18 -2
  25. data/lib/moov/models/components/issuingcontrols.rbi +8 -0
  26. data/lib/moov/models/components/issuingcontrols_allowedschedule.rb +36 -0
  27. data/lib/moov/models/components/issuingcontrols_allowedschedule.rbi +15 -0
  28. data/lib/moov/models/components/issuingcontrolserror.rb +18 -2
  29. data/lib/moov/models/components/issuingcontrolserror.rbi +8 -0
  30. data/lib/moov/models/components/issuingcontrolsrestrictionmode.rb +19 -0
  31. data/lib/moov/models/components/issuingcontrolsrestrictionmode.rbi +11 -0
  32. data/lib/moov/models/components/issuingintervallimit.rb +4 -1
  33. data/lib/moov/models/components/issuingmerchantcategory.rb +43 -0
  34. data/lib/moov/models/components/issuingmerchantcategory.rbi +11 -0
  35. data/lib/moov/models/components/issuingscheduleday.rb +24 -0
  36. data/lib/moov/models/components/issuingscheduleday.rbi +11 -0
  37. data/lib/moov/models/components/issuingvelocitylimit.rb +11 -7
  38. data/lib/moov/models/components/issuingvelocitylimit.rbi +4 -2
  39. data/lib/moov/models/components/issuingvelocitylimiterror.rb +6 -2
  40. data/lib/moov/models/components/issuingvelocitylimiterror.rbi +2 -0
  41. data/lib/moov/models/components/merchantcategoryrestrictions.rb +44 -0
  42. data/lib/moov/models/components/merchantcategoryrestrictions.rbi +19 -0
  43. data/lib/moov/models/components/merchantcategoryrestrictionserror.rb +44 -0
  44. data/lib/moov/models/components/merchantcategoryrestrictionserror.rbi +19 -0
  45. data/lib/moov/models/components/merchantentry.rb +40 -0
  46. data/lib/moov/models/components/merchantentry.rbi +17 -0
  47. data/lib/moov/models/components/merchantentryerror.rb +36 -0
  48. data/lib/moov/models/components/merchantentryerror.rbi +15 -0
  49. data/lib/moov/models/components/merchantrestrictions.rb +36 -0
  50. data/lib/moov/models/components/merchantrestrictions.rbi +15 -0
  51. data/lib/moov/models/components/merchantrestrictionserror.rb +36 -0
  52. data/lib/moov/models/components/merchantrestrictionserror.rbi +15 -0
  53. data/lib/moov/models/components/paymentlinkpayoutdetails.rb +8 -2
  54. data/lib/moov/models/components/paymentlinkpayoutdetails.rbi +2 -0
  55. data/lib/moov/models/components/paymentlinkpayoutdetailsupdate.rb +8 -2
  56. data/lib/moov/models/components/paymentlinkpayoutdetailsupdate.rbi +2 -0
  57. data/lib/moov/models/components/payoutdetailserror.rb +6 -2
  58. data/lib/moov/models/components/payoutdetailserror.rbi +2 -0
  59. data/lib/moov/models/components/product.rb +6 -2
  60. data/lib/moov/models/components/product.rbi +2 -0
  61. data/lib/moov/models/components/productcategories.rb +32 -0
  62. data/lib/moov/models/components/productcategories.rbi +13 -0
  63. data/lib/moov/models/components/productcategory.rb +48 -0
  64. data/lib/moov/models/components/productcategory.rbi +21 -0
  65. data/lib/moov/models/components/productrequest.rb +6 -2
  66. data/lib/moov/models/components/productrequest.rbi +2 -0
  67. data/lib/moov/models/components/schedulewindow.rb +40 -0
  68. data/lib/moov/models/components/schedulewindow.rbi +17 -0
  69. data/lib/moov/models/components/schedulewindowerror.rb +40 -0
  70. data/lib/moov/models/components/schedulewindowerror.rbi +17 -0
  71. data/lib/moov/models/components/schemebasicauth.rb +36 -0
  72. data/lib/moov/models/components/schemebasicauth.rbi +15 -0
  73. data/lib/moov/models/components/schemeoauth2auth.rb +40 -0
  74. data/lib/moov/models/components/schemeoauth2auth.rbi +17 -0
  75. data/lib/moov/models/components/transferfeepaidby.rb +32 -0
  76. data/lib/moov/models/components/transferfeepaidby.rbi +13 -0
  77. data/lib/moov/models/components/updateissuedcard.rb +6 -2
  78. data/lib/moov/models/components/updateissuedcard.rbi +2 -0
  79. data/lib/moov/models/components/updateissuingcontrols.rb +48 -0
  80. data/lib/moov/models/components/updateissuingcontrols.rbi +21 -0
  81. data/lib/moov/models/components/updateissuingcontrols_allowedschedule.rb +36 -0
  82. data/lib/moov/models/components/updateissuingcontrols_allowedschedule.rbi +15 -0
  83. data/lib/moov/models/components/updateissuingcontrols_merchantcategoryrestrictions.rb +44 -0
  84. data/lib/moov/models/components/updateissuingcontrols_merchantcategoryrestrictions.rbi +19 -0
  85. data/lib/moov/models/components/updateissuingcontrols_merchantrestrictions.rb +36 -0
  86. data/lib/moov/models/components/updateissuingcontrols_merchantrestrictions.rbi +15 -0
  87. data/lib/moov/models/components/updateissuingcontrolserror.rb +48 -0
  88. data/lib/moov/models/components/updateissuingcontrolserror.rbi +21 -0
  89. data/lib/moov/models/components.rb +29 -0
  90. data/lib/moov/models/errors/productrequestvalidationerror.rb +6 -2
  91. data/lib/moov/models/errors/productrequestvalidationerror.rbi +2 -0
  92. data/lib/moov/models/errors/updateissuedcarderror.rb +6 -2
  93. data/lib/moov/models/errors/updateissuedcarderror.rbi +2 -0
  94. data/lib/moov/models/operations/deleteavatar_request.rb +32 -0
  95. data/lib/moov/models/operations/deleteavatar_request.rbi +13 -0
  96. data/lib/moov/models/operations/deleteavatar_response.rb +44 -0
  97. data/lib/moov/models/operations/deleteavatar_response.rbi +19 -0
  98. data/lib/moov/models/operations/deleteavatar_security.rb +36 -0
  99. data/lib/moov/models/operations/deleteavatar_security.rbi +15 -0
  100. data/lib/moov/models/operations/listproductcategories_response.rb +48 -0
  101. data/lib/moov/models/operations/listproductcategories_response.rbi +21 -0
  102. data/lib/moov/models/operations/listproducts_request.rb +8 -2
  103. data/lib/moov/models/operations/listproducts_request.rbi +2 -0
  104. data/lib/moov/models/operations/uploadavatar_request.rb +36 -0
  105. data/lib/moov/models/operations/uploadavatar_request.rbi +15 -0
  106. data/lib/moov/models/operations/uploadavatar_response.rb +44 -0
  107. data/lib/moov/models/operations/uploadavatar_response.rbi +19 -0
  108. data/lib/moov/models/operations/uploadavatar_security.rb +36 -0
  109. data/lib/moov/models/operations/uploadavatar_security.rbi +15 -0
  110. data/lib/moov/models/operations.rb +7 -0
  111. data/lib/moov/products.rb +113 -8
  112. data/lib/moov/sdk_hooks/clientcredentials.rb +386 -0
  113. data/lib/moov/sdk_hooks/hooks.rb +6 -0
  114. data/lib/moov/sdk_hooks/oauth2scopes.rb +18 -0
  115. data/lib/moov/sdkconfiguration.rb +3 -3
  116. metadata +76 -2
@@ -66,6 +66,9 @@ module Moov
66
66
  autoload :CreateWalletRequest, 'moov/models/operations/createwallet_request.rb'
67
67
  autoload :CreateWalletResponse, 'moov/models/operations/createwallet_response.rb'
68
68
  autoload :CreateWebhookResponse, 'moov/models/operations/createwebhook_response.rb'
69
+ autoload :DeleteAvatarSecurity, 'moov/models/operations/deleteavatar_security.rb'
70
+ autoload :DeleteAvatarRequest, 'moov/models/operations/deleteavatar_request.rb'
71
+ autoload :DeleteAvatarResponse, 'moov/models/operations/deleteavatar_response.rb'
69
72
  autoload :DeleteDisputeEvidenceFileRequest, 'moov/models/operations/deletedisputeevidencefile_request.rb'
70
73
  autoload :DeleteDisputeEvidenceFileResponse, 'moov/models/operations/deletedisputeevidencefile_response.rb'
71
74
  autoload :DeleteImageRequest, 'moov/models/operations/deleteimage_request.rb'
@@ -270,6 +273,7 @@ module Moov
270
273
  autoload :ListPaymentLinksResponse, 'moov/models/operations/listpaymentlinks_response.rb'
271
274
  autoload :ListPaymentMethodsRequest, 'moov/models/operations/listpaymentmethods_request.rb'
272
275
  autoload :ListPaymentMethodsResponse, 'moov/models/operations/listpaymentmethods_response.rb'
276
+ autoload :ListProductCategoriesResponse, 'moov/models/operations/listproductcategories_response.rb'
273
277
  autoload :ListProductsRequest, 'moov/models/operations/listproducts_request.rb'
274
278
  autoload :ListProductsResponse, 'moov/models/operations/listproducts_response.rb'
275
279
  autoload :ListReceiptsRequest, 'moov/models/operations/listreceipts_request.rb'
@@ -362,6 +366,9 @@ module Moov
362
366
  autoload :UpdateWalletResponse, 'moov/models/operations/updatewallet_response.rb'
363
367
  autoload :UpdateWebhookRequest, 'moov/models/operations/updatewebhook_request.rb'
364
368
  autoload :UpdateWebhookResponse, 'moov/models/operations/updatewebhook_response.rb'
369
+ autoload :UploadAvatarSecurity, 'moov/models/operations/uploadavatar_security.rb'
370
+ autoload :UploadAvatarRequest, 'moov/models/operations/uploadavatar_request.rb'
371
+ autoload :UploadAvatarResponse, 'moov/models/operations/uploadavatar_response.rb'
365
372
  autoload :UploadDisputeEvidenceFileRequest, 'moov/models/operations/uploaddisputeevidencefile_request.rb'
366
373
  autoload :UploadDisputeEvidenceFileResponse, 'moov/models/operations/uploaddisputeevidencefile_response.rb'
367
374
  autoload :UploadDisputeEvidenceTextRequest, 'moov/models/operations/uploaddisputeevidencetext_request.rb'
data/lib/moov/products.rb CHANGED
@@ -41,15 +41,9 @@ module Moov
41
41
 
42
42
 
43
43
 
44
- sig { params(account_id: ::String, title: T.nilable(::String), skip: T.nilable(::Integer), count: T.nilable(::Integer), timeout_ms: T.nilable(Integer), http_headers: T.nilable(T::Hash[T.any(String, Symbol), String])).returns(Models::Operations::ListProductsResponse) }
45
- def list(account_id:, title: nil, skip: nil, count: nil, timeout_ms: nil, http_headers: nil)
44
+ sig { params(request: Models::Operations::ListProductsRequest, timeout_ms: T.nilable(Integer), http_headers: T.nilable(T::Hash[T.any(String, Symbol), String])).returns(Models::Operations::ListProductsResponse) }
45
+ def list(request:, timeout_ms: nil, http_headers: nil)
46
46
  # list - List active (non-disabled) products for an account.
47
- request = Models::Operations::ListProductsRequest.new(
48
- account_id: account_id,
49
- title: title,
50
- skip: skip,
51
- count: count
52
- )
53
47
  url, params = @sdk_configuration.get_server_details
54
48
  base_url = Utils.template_url(url, params)
55
49
  url = Utils.generate_url(
@@ -736,5 +730,116 @@ module Moov
736
730
 
737
731
  end
738
732
  end
733
+
734
+
735
+ sig { params(timeout_ms: T.nilable(Integer), http_headers: T.nilable(T::Hash[T.any(String, Symbol), String])).returns(Models::Operations::ListProductCategoriesResponse) }
736
+ def list_categories(timeout_ms: nil, http_headers: nil)
737
+ # list_categories - Returns the full, read-only list of product categories from the product taxonomy.
738
+ url, params = @sdk_configuration.get_server_details
739
+ base_url = Utils.template_url(url, params)
740
+ url = "#{base_url}/product-categories"
741
+ headers = {}
742
+ headers = T.cast(headers, T::Hash[String, String])
743
+ headers['Accept'] = 'application/json'
744
+ headers['user-agent'] = @sdk_configuration.user_agent
745
+
746
+ security = @sdk_configuration.security_source&.call
747
+
748
+ timeout = (timeout_ms.to_f / 1000) unless timeout_ms.nil?
749
+ timeout ||= @sdk_configuration.timeout
750
+
751
+
752
+ connection = @sdk_configuration.client
753
+
754
+ hook_ctx = SDKHooks::HookContext.new(
755
+ config: @sdk_configuration,
756
+ base_url: base_url,
757
+ oauth2_scopes: nil,
758
+ operation_id: 'listProductCategories',
759
+ security_source: @sdk_configuration.security_source
760
+ )
761
+
762
+ error = T.let(nil, T.nilable(StandardError))
763
+ http_response = T.let(nil, T.nilable(Faraday::Response))
764
+
765
+
766
+ begin
767
+ http_response = T.must(connection).get(url) do |req|
768
+ req.headers.merge!(headers)
769
+ req.options.timeout = timeout unless timeout.nil?
770
+ Utils.configure_request_security(req, security)
771
+ http_headers&.each do |key, value|
772
+ req.headers[key.to_s] = value
773
+ end
774
+
775
+ @sdk_configuration.hooks.before_request(
776
+ hook_ctx: SDKHooks::BeforeRequestHookContext.new(
777
+ hook_ctx: hook_ctx
778
+ ),
779
+ request: req
780
+ )
781
+ end
782
+ rescue StandardError => e
783
+ error = e
784
+ ensure
785
+ if http_response.nil? || Utils.error_status?(http_response.status)
786
+ http_response = @sdk_configuration.hooks.after_error(
787
+ error: error,
788
+ hook_ctx: SDKHooks::AfterErrorHookContext.new(
789
+ hook_ctx: hook_ctx
790
+ ),
791
+ response: http_response
792
+ )
793
+ else
794
+ http_response = @sdk_configuration.hooks.after_success(
795
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
796
+ hook_ctx: hook_ctx
797
+ ),
798
+ response: http_response
799
+ )
800
+ end
801
+
802
+ if http_response.nil?
803
+ raise error if !error.nil?
804
+ raise 'no response'
805
+ end
806
+ end
807
+
808
+ content_type = http_response.headers.fetch('Content-Type', 'application/octet-stream')
809
+ if Utils.match_status_code(http_response.status, ['200'])
810
+ if Utils.match_content_type(content_type, 'application/json')
811
+ http_response = @sdk_configuration.hooks.after_success(
812
+ hook_ctx: SDKHooks::AfterSuccessHookContext.new(
813
+ hook_ctx: hook_ctx
814
+ ),
815
+ response: http_response
816
+ )
817
+ response_data = http_response.env.response_body
818
+ obj = Crystalline.unmarshal_json(JSON.parse(response_data), Models::Components::ProductCategories)
819
+ response = Models::Operations::ListProductCategoriesResponse.new(
820
+ status_code: http_response.status,
821
+ content_type: content_type,
822
+ raw_response: http_response,
823
+ headers: http_response.headers,
824
+ product_categories: T.unsafe(obj)
825
+ )
826
+
827
+ return response
828
+ else
829
+ raise ::Moov::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown content type received'
830
+ end
831
+ elsif Utils.match_status_code(http_response.status, ['401', '403', '429'])
832
+ raise ::Moov::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'API error occurred'
833
+ elsif Utils.match_status_code(http_response.status, ['500', '504'])
834
+ raise ::Moov::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'API error occurred'
835
+ elsif Utils.match_status_code(http_response.status, ['4XX'])
836
+ raise ::Moov::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'API error occurred'
837
+ elsif Utils.match_status_code(http_response.status, ['5XX'])
838
+ raise ::Moov::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'API error occurred'
839
+ else
840
+ raise ::Moov::Models::Errors::APIError.new(status_code: http_response.status, body: http_response.env.response_body, raw_response: http_response), 'Unknown status code received'
841
+
842
+ end
843
+ end
739
844
  end
740
845
  end
@@ -0,0 +1,386 @@
1
+ # Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
2
+
3
+ # typed: true
4
+ # frozen_string_literal: true
5
+
6
+ require 'digest'
7
+ require 'json'
8
+ require 'net/http'
9
+ require 'uri'
10
+
11
+ require_relative './types'
12
+
13
+ module Moov
14
+ module SDKHooks
15
+ class Credentials
16
+ extend T::Sig
17
+
18
+ sig { returns(String) }
19
+ attr_reader :client_id
20
+
21
+ sig { returns(String) }
22
+ attr_reader :client_secret
23
+
24
+ sig { returns(String) }
25
+ attr_reader :token_url
26
+
27
+ sig { returns(T.nilable(T::Array[String])) }
28
+ attr_reader :scopes
29
+
30
+ sig { returns(T::Hash[String, String]) }
31
+ attr_reader :additional_properties
32
+
33
+ sig do
34
+ params(
35
+ client_id: String,
36
+ client_secret: String,
37
+ token_url: String,
38
+ scopes: T.nilable(T::Array[String]),
39
+ additional_properties: T::Hash[String, String]
40
+ ).void
41
+ end
42
+ def initialize(client_id:, client_secret:, token_url:, scopes: nil, additional_properties: {})
43
+ @client_id = client_id
44
+ @client_secret = client_secret
45
+ @token_url = token_url
46
+ @scopes = scopes
47
+ @additional_properties = additional_properties
48
+ end
49
+ end
50
+
51
+ class Session
52
+ extend T::Sig
53
+
54
+ sig { returns(Credentials) }
55
+ attr_reader :credentials
56
+
57
+ sig { returns(String) }
58
+ attr_reader :token
59
+
60
+ sig { returns(T::Array[String]) }
61
+ attr_reader :scopes
62
+
63
+ sig { returns(T.nilable(Integer)) }
64
+ attr_reader :expires_at
65
+
66
+ sig do
67
+ params(
68
+ credentials: Credentials,
69
+ token: String,
70
+ scopes: T::Array[String],
71
+ expires_at: T.nilable(Integer)
72
+ ).void
73
+ end
74
+ def initialize(credentials:, token:, scopes:, expires_at: nil)
75
+ @credentials = credentials
76
+ @token = token
77
+ @scopes = scopes
78
+ @expires_at = expires_at
79
+ end
80
+ end
81
+
82
+ class ClientCredentialsHook < AbstractSDKHook
83
+
84
+ extend T::Sig
85
+
86
+ @global_lock = Mutex.new
87
+ @client_locks = {}
88
+ @sessions = {}
89
+
90
+ class << self
91
+ attr_reader :global_lock
92
+ attr_accessor :client_locks, :sessions
93
+ end
94
+
95
+ sig { override.params(config: SDKConfiguration).returns(SDKConfiguration) }
96
+ def sdk_init(config:)
97
+ raise 'Client is required' if config.client.nil?
98
+
99
+ @client = config.client
100
+ config
101
+ end
102
+
103
+ sig do
104
+ override.params(
105
+ hook_ctx: BeforeRequestHookContext,
106
+ request: Faraday::Request
107
+ ).returns(Faraday::Request)
108
+ end
109
+ def before_request(hook_ctx:, request:)
110
+ return request if hook_disabled?(hook_ctx)
111
+
112
+ credentials = get_credentials(hook_ctx)
113
+ return request if credentials.nil?
114
+
115
+ session_key = get_session_key(credentials.client_id, credentials.client_secret)
116
+ scopes = get_required_scopes(credentials, hook_ctx)
117
+ session = get_existing_session(session_key, scopes)
118
+
119
+ if session.nil?
120
+ token_url = resolve_token_endpoint(hook_ctx.base_url, credentials.token_url)
121
+ session = do_token_request(token_url, credentials, scopes)
122
+ store_session(session_key, scopes, session)
123
+ end
124
+
125
+ request.headers['Authorization'] = "Bearer #{session.token}"
126
+ request
127
+ end
128
+
129
+ sig do
130
+ override.params(
131
+ error: T.nilable(StandardError),
132
+ hook_ctx: AfterErrorHookContext,
133
+ response: T.nilable(Faraday::Response)
134
+ ).returns(T.nilable(Faraday::Response))
135
+ end
136
+ def after_error(error:, hook_ctx:, response:)
137
+ return response if hook_disabled?(hook_ctx)
138
+
139
+ # We don't want to refresh the token if the error is not related to the token
140
+ return response unless error.nil?
141
+
142
+ credentials = get_credentials(hook_ctx)
143
+ return response if credentials.nil?
144
+
145
+ if !response.nil? && response.status == 401
146
+ session_key = get_session_key(credentials.client_id, credentials.client_secret)
147
+ scopes = get_required_scopes(credentials, hook_ctx)
148
+ scope_key = get_scope_key(scopes)
149
+ remove_session(session_key, scope_key)
150
+ end
151
+
152
+ response
153
+ end
154
+
155
+ private
156
+
157
+ sig { params(hook_ctx: HookContext).returns(T::Boolean) }
158
+ def hook_disabled?(hook_ctx)
159
+ hook_ctx.oauth2_scopes.nil?
160
+ end
161
+
162
+
163
+ sig { params(hook_ctx: HookContext).returns(T.nilable(Credentials)) }
164
+ def get_credentials(hook_ctx)
165
+ source = hook_ctx.security_source
166
+ return nil if source.nil?
167
+
168
+ security = source.call
169
+
170
+ case hook_ctx.operation_id
171
+ when 'uploadAvatar'
172
+ return get_credentials_upload_avatar(security)
173
+ when 'deleteAvatar'
174
+ return get_credentials_delete_avatar(security)
175
+ end
176
+
177
+ nil
178
+ end
179
+
180
+
181
+ sig { params(security: T.untyped).returns(T.nilable(Credentials)) }
182
+ def get_credentials_upload_avatar(security)
183
+ return nil if security.nil? || security.o_auth2_auth.nil?
184
+
185
+ # Extract additional properties from security object
186
+ additional_properties = {}
187
+ security.o_auth2_auth.class.fields.each do |f|
188
+ name = f.name.to_s
189
+ next if %w[client_id client_secret token_url scopes].include?(name)
190
+
191
+ metadata = f.metadata&.dig(:security)
192
+ next if metadata.nil?
193
+
194
+ field_name = metadata[:field_name] || name
195
+ value = security.o_auth2_auth.send(f.name)
196
+ additional_properties[field_name] = value.to_s unless value.nil?
197
+ end
198
+
199
+ Credentials.new(
200
+ client_id: security.o_auth2_auth.client_id,
201
+ client_secret: security.o_auth2_auth.client_secret,
202
+ token_url: security.o_auth2_auth.token_url,
203
+ scopes: nil,
204
+ additional_properties: additional_properties
205
+ )
206
+ end
207
+
208
+ sig { params(security: T.untyped).returns(T.nilable(Credentials)) }
209
+ def get_credentials_delete_avatar(security)
210
+ return nil if security.nil? || security.o_auth2_auth.nil?
211
+
212
+ # Extract additional properties from security object
213
+ additional_properties = {}
214
+ security.o_auth2_auth.class.fields.each do |f|
215
+ name = f.name.to_s
216
+ next if %w[client_id client_secret token_url scopes].include?(name)
217
+
218
+ metadata = f.metadata&.dig(:security)
219
+ next if metadata.nil?
220
+
221
+ field_name = metadata[:field_name] || name
222
+ value = security.o_auth2_auth.send(f.name)
223
+ additional_properties[field_name] = value.to_s unless value.nil?
224
+ end
225
+
226
+ Credentials.new(
227
+ client_id: security.o_auth2_auth.client_id,
228
+ client_secret: security.o_auth2_auth.client_secret,
229
+ token_url: security.o_auth2_auth.token_url,
230
+ scopes: nil,
231
+ additional_properties: additional_properties
232
+ )
233
+ end
234
+
235
+
236
+ sig { params(base_url: String, token_url: String).returns(String) }
237
+ def resolve_token_endpoint(base_url, token_url)
238
+ parsed = URI.parse(token_url)
239
+ return token_url if parsed.host
240
+
241
+ base = base_url.chomp('/')
242
+ URI.join("#{base}/", token_url).to_s
243
+ end
244
+
245
+ sig { params(token_url: String, credentials: Credentials, scopes: T::Array[String]).returns(Session) }
246
+ def do_token_request(token_url, credentials, scopes)
247
+ payload = {
248
+ 'grant_type' => 'client_credentials',
249
+ 'client_id' => credentials.client_id,
250
+ 'client_secret' => credentials.client_secret
251
+ }
252
+
253
+ payload['scope'] = scopes.join(' ') unless scopes.empty?
254
+
255
+ # Add additional properties to payload
256
+ credentials.additional_properties.each do |key, value|
257
+ payload[key] = value
258
+ end
259
+ response = @client.post(token_url) do |req|
260
+ req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
261
+ req.body = URI.encode_www_form(payload)
262
+ end
263
+
264
+ raise "Unexpected status code #{response.status} from token endpoint" unless response.status >= 200 && response.status < 300
265
+
266
+ response_data = JSON.parse(response.body)
267
+
268
+ raise 'Unexpected token type from token endpoint' unless response_data.fetch('token_type', '').downcase == 'bearer'
269
+
270
+ expires_at = nil
271
+ if response_data.key?('expires_in')
272
+ expires_at = Time.now.to_i + response_data['expires_in'].to_i
273
+ end
274
+
275
+ Session.new(
276
+ credentials: credentials,
277
+ token: response_data['access_token'],
278
+ scopes: scopes,
279
+ expires_at: expires_at
280
+ )
281
+ end
282
+
283
+ sig { params(client_id: String, client_secret: String).returns(String) }
284
+ def get_session_key(client_id, client_secret)
285
+ Digest::MD5.hexdigest("#{client_id}:#{client_secret}")
286
+ end
287
+
288
+ sig { params(credentials: Credentials, hook_ctx: HookContext).returns(T::Array[String]) }
289
+ def get_required_scopes(credentials, hook_ctx)
290
+ return T.must(credentials.scopes) unless credentials.scopes.nil?
291
+
292
+ hook_ctx.oauth2_scopes || []
293
+ end
294
+
295
+ sig { params(scopes: T::Array[String]).returns(String) }
296
+ def get_scope_key(scopes)
297
+ return '' if scopes.empty?
298
+
299
+ scopes.sort.join('&')
300
+ end
301
+
302
+ sig { params(client_key: String, scopes: T::Array[String], session: Session).void }
303
+ def store_session(client_key, scopes, session)
304
+ scope_key = get_scope_key(scopes)
305
+ lock = get_client_lock(client_key)
306
+ lock.synchronize do
307
+ self.class.sessions[client_key] ||= {}
308
+ self.class.sessions[client_key][scope_key] = session
309
+ end
310
+ end
311
+
312
+ sig { params(client_key: String, scope_key: String).void }
313
+ def remove_session(client_key, scope_key)
314
+ lock = get_client_lock(client_key)
315
+ lock.synchronize do
316
+ if self.class.sessions.key?(client_key) && self.class.sessions[client_key].key?(scope_key)
317
+ self.class.sessions[client_key].delete(scope_key)
318
+ self.class.sessions.delete(client_key) if self.class.sessions[client_key].empty?
319
+ end
320
+ end
321
+ end
322
+
323
+ sig { params(client_key: String, required_scopes: T::Array[String]).returns(T.nilable(Session)) }
324
+ def get_existing_session(client_key, required_scopes)
325
+ scope_key = get_scope_key(required_scopes)
326
+ expired_keys = []
327
+ result = T.let(nil, T.untyped)
328
+
329
+ lock = get_client_lock(client_key)
330
+ lock.synchronize do
331
+ return nil unless self.class.sessions.key?(client_key)
332
+
333
+ client_sessions = self.class.sessions[client_key]
334
+
335
+ # Check for exact scope match first
336
+ if client_sessions.key?(scope_key)
337
+ exact_match = client_sessions[scope_key]
338
+ if token_expired?(exact_match.expires_at)
339
+ expired_keys << scope_key
340
+ else
341
+ result = exact_match
342
+ end
343
+ end
344
+
345
+ # If no exact match, look for a superset match
346
+ if result.nil?
347
+ found = T.let(false, T::Boolean)
348
+ client_sessions.each do |key, session|
349
+ if token_expired?(session.expires_at)
350
+ expired_keys << key
351
+ elsif !found && required_scopes?(session.scopes, required_scopes)
352
+ result = session
353
+ found = true
354
+ end
355
+ end
356
+ end
357
+
358
+ # Clean up expired sessions
359
+ expired_keys.each { |key| client_sessions.delete(key) }
360
+
361
+ # Clean up empty client sessions
362
+ self.class.sessions.delete(client_key) if self.class.sessions.key?(client_key) && self.class.sessions[client_key].empty?
363
+ end
364
+
365
+ result
366
+ end
367
+
368
+ sig { params(scopes: T::Array[String], required_scopes: T::Array[String]).returns(T::Boolean) }
369
+ def required_scopes?(scopes, required_scopes)
370
+ required_scopes.all? { |scope| scopes.include?(scope) }
371
+ end
372
+
373
+ sig { params(expires_at: T.nilable(Integer)).returns(T::Boolean) }
374
+ def token_expired?(expires_at)
375
+ !expires_at.nil? && Time.now.to_i + 60 >= expires_at
376
+ end
377
+
378
+ sig { params(client_key: String).returns(Mutex) }
379
+ def get_client_lock(client_key)
380
+ self.class.global_lock.synchronize do
381
+ self.class.client_locks[client_key] ||= Mutex.new
382
+ end
383
+ end
384
+ end
385
+ end
386
+ end
@@ -5,6 +5,8 @@
5
5
 
6
6
  require_relative './types'
7
7
  require_relative './registration'
8
+ require_relative './oauth2scopes'
9
+ require_relative './clientcredentials'
8
10
 
9
11
  module Moov
10
12
  module SDKHooks
@@ -17,6 +19,10 @@ module Moov
17
19
  @before_request_hooks = T.let([], T::Array[AbstractSDKHook])
18
20
  @after_success_hooks = T.let([], T::Array[AbstractSDKHook])
19
21
  @after_error_hooks = T.let([], T::Array[AbstractSDKHook])
22
+ cc_hook = ClientCredentialsHook.new
23
+ register_sdk_init_hook cc_hook
24
+ register_before_request_hook cc_hook
25
+ register_after_error_hook cc_hook
20
26
  Registration.init_hooks self
21
27
  end
22
28
 
@@ -0,0 +1,18 @@
1
+ # Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
2
+
3
+ # typed: true
4
+ # frozen_string_literal: true
5
+
6
+ module Moov
7
+ module SDKHooks
8
+
9
+ # OAuth2AuthOAuth2Scope - Available scopes for the OAuth2Auth OAuth 2.0 scheme (clientCredentials flow).
10
+ class OAuth2AuthOAuth2Scope < T::Enum
11
+
12
+ enums do
13
+ # ROOT_ACCOUNTS_WRITE
14
+ ROOT_ACCOUNTS_WRITE = new('/accounts.write')
15
+ end
16
+ end
17
+ end
18
+ end
@@ -88,9 +88,9 @@ module Moov
88
88
  end
89
89
  @language = 'ruby'
90
90
  @openapi_doc_version = 'dev'
91
- @sdk_version = '0.0.0-dev.23'
92
- @gen_version = '2.917.0'
93
- @user_agent = 'speakeasy-sdk/ruby 0.0.0-dev.23 2.917.0 dev moov_ruby'
91
+ @sdk_version = '0.0.0-dev.24'
92
+ @gen_version = '2.924.0'
93
+ @user_agent = 'speakeasy-sdk/ruby 0.0.0-dev.24 2.924.0 dev moov_ruby'
94
94
  end
95
95
 
96
96
  sig { returns([String, T::Hash[Symbol, String]]) }