inttegro 3.0.1 → 4.2.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +27 -0
- data/README.md +19 -2
- data/lib/inttegro/client.rb +9 -3
- data/lib/inttegro/generated/enums.rb +68 -14
- data/lib/inttegro/generated/models.rb +358 -207
- data/lib/inttegro/generated/operations.rb +13 -1
- data/lib/inttegro/http_client.rb +101 -63
- data/lib/inttegro/models.rb +52 -0
- data/lib/inttegro/resources/orders.rb +1 -1
- data/lib/inttegro/resources/prices.rb +6 -6
- data/lib/inttegro/resources/products.rb +1 -1
- data/lib/inttegro/resources/upload_requests.rb +2 -1
- data/lib/inttegro/telemetry.rb +156 -0
- data/lib/inttegro/version.rb +1 -1
- data/rbi/inttegro/generated.rbi +7 -7
- data/rbi/opentelemetry-api.rbi +77 -0
- metadata +18 -2
|
@@ -31,6 +31,10 @@ module Inttegro
|
|
|
31
31
|
"/customers/lookup" => Inttegro::CustomerResponse,
|
|
32
32
|
"/customers/update" => Inttegro::CustomerResponse,
|
|
33
33
|
"/customers/page" => Inttegro::PageCustomersResponse,
|
|
34
|
+
"/checkout/lookup" => Inttegro::CheckoutOrderResponse,
|
|
35
|
+
"/checkout/pay" => Inttegro::CheckoutOrderResponse,
|
|
36
|
+
"/checkout/confirm_payment" => Inttegro::CheckoutOrderResponse,
|
|
37
|
+
"/checkout/request_confirmation" => Inttegro::CheckoutOrderResponse,
|
|
34
38
|
"/orders/create" => Inttegro::OrderEnvelope,
|
|
35
39
|
"/orders/lookup" => Inttegro::OrderEnvelope,
|
|
36
40
|
"/orders/update" => Inttegro::OrderEnvelope,
|
|
@@ -150,6 +154,10 @@ module Inttegro
|
|
|
150
154
|
"/customers/lookup" => "Inttegro::LookupCustomerRequest",
|
|
151
155
|
"/customers/update" => "Inttegro::UpdateCustomerRequest",
|
|
152
156
|
"/customers/page" => "Inttegro::PageCustomersRequest",
|
|
157
|
+
"/checkout/lookup" => "Inttegro::CheckoutOrderReferenceRequest",
|
|
158
|
+
"/checkout/pay" => "Inttegro::CheckoutPayRequest",
|
|
159
|
+
"/checkout/confirm_payment" => "Inttegro::CheckoutConfirmPaymentRequest",
|
|
160
|
+
"/checkout/request_confirmation" => "Inttegro::CheckoutOrderReferenceRequest",
|
|
153
161
|
"/orders/create" => "T.any(Inttegro::CreateOrderNewCustomer, Inttegro::CreateOrderExistingCustomer)",
|
|
154
162
|
"/orders/lookup" => "Inttegro::LookupOrderRequest",
|
|
155
163
|
"/orders/update" => "Inttegro::UpdateOrderRequest",
|
|
@@ -233,7 +241,7 @@ module Inttegro
|
|
|
233
241
|
"/purchase_intents/cancel" => "Inttegro::CancelPurchaseIntentRequest",
|
|
234
242
|
"/purchase_intents/lookup" => "Inttegro::LookupPurchaseIntentRequest",
|
|
235
243
|
"/purchase_intents/page" => "Inttegro::PagePurchaseIntentsRequest",
|
|
236
|
-
"/prices/create" => "Inttegro::
|
|
244
|
+
"/prices/create" => "Inttegro::CatalogPriceParams",
|
|
237
245
|
"/prices/lookup" => "Inttegro::LookupPriceRequest",
|
|
238
246
|
"/prices/page" => "Inttegro::PricePageRequest",
|
|
239
247
|
"/prices/update" => "Inttegro::UpdatePriceRequest",
|
|
@@ -267,6 +275,10 @@ module Inttegro
|
|
|
267
275
|
"/customers/lookup" => "lookupCustomer",
|
|
268
276
|
"/customers/update" => "updateCustomer",
|
|
269
277
|
"/customers/page" => "pageCustomers",
|
|
278
|
+
"/checkout/lookup" => "lookupCheckoutOrder",
|
|
279
|
+
"/checkout/pay" => "payCheckoutOrder",
|
|
280
|
+
"/checkout/confirm_payment" => "confirmCheckoutPayment",
|
|
281
|
+
"/checkout/request_confirmation" => "requestCheckoutConfirmation",
|
|
270
282
|
"/orders/create" => "createOrder",
|
|
271
283
|
"/orders/lookup" => "lookupOrder",
|
|
272
284
|
"/orders/update" => "updateOrder",
|
data/lib/inttegro/http_client.rb
CHANGED
|
@@ -12,6 +12,7 @@ require_relative "models"
|
|
|
12
12
|
require_relative "generated/operations"
|
|
13
13
|
require_relative "response_object"
|
|
14
14
|
require_relative "transport_response"
|
|
15
|
+
require_relative "telemetry"
|
|
15
16
|
require_relative "types"
|
|
16
17
|
require_relative "version"
|
|
17
18
|
|
|
@@ -34,10 +35,20 @@ module Inttegro
|
|
|
34
35
|
base_url: T.nilable(String),
|
|
35
36
|
read_timeout: T.nilable(Numeric),
|
|
36
37
|
open_timeout: T.nilable(Numeric),
|
|
37
|
-
adapter: T.nilable(Types::Adapter)
|
|
38
|
+
adapter: T.nilable(Types::Adapter),
|
|
39
|
+
telemetry_enabled: T::Boolean,
|
|
40
|
+
tracer_provider: T.nilable(OpenTelemetry::Trace::TracerProvider)
|
|
38
41
|
).void
|
|
39
42
|
end
|
|
40
|
-
def initialize(
|
|
43
|
+
def initialize(
|
|
44
|
+
api_key:,
|
|
45
|
+
base_url: DEFAULT_BASE_URL,
|
|
46
|
+
read_timeout: 30,
|
|
47
|
+
open_timeout: 10,
|
|
48
|
+
adapter: nil,
|
|
49
|
+
telemetry_enabled: true,
|
|
50
|
+
tracer_provider: nil
|
|
51
|
+
)
|
|
41
52
|
@api_key = T.let(api_key || "", String)
|
|
42
53
|
raise ArgumentError, "api_key is required" if @api_key.strip.empty?
|
|
43
54
|
|
|
@@ -48,6 +59,10 @@ module Inttegro
|
|
|
48
59
|
@read_timeout = T.let(read_timeout, T.nilable(Numeric))
|
|
49
60
|
@open_timeout = T.let(open_timeout, T.nilable(Numeric))
|
|
50
61
|
@adapter = T.let(adapter, T.nilable(Types::Adapter))
|
|
62
|
+
@telemetry = T.let(
|
|
63
|
+
Telemetry.new(Inttegro::VERSION, enabled: telemetry_enabled, tracer_provider: tracer_provider),
|
|
64
|
+
Telemetry
|
|
65
|
+
)
|
|
51
66
|
end
|
|
52
67
|
|
|
53
68
|
sig { params(path: String, headers: Types::Headers, query: T.nilable(Types::Query)).returns(ResponseValue) }
|
|
@@ -165,16 +180,17 @@ module Inttegro
|
|
|
165
180
|
fields: Types::Payload,
|
|
166
181
|
files: Types::Payload,
|
|
167
182
|
headers: Types::Headers,
|
|
168
|
-
authenticated: T::Boolean
|
|
183
|
+
authenticated: T::Boolean,
|
|
184
|
+
operation: T.nilable(String)
|
|
169
185
|
)
|
|
170
186
|
.returns(T.type_parameter(:Model))
|
|
171
187
|
end
|
|
172
|
-
def post_multipart_model(path, model, fields: {}, files: {}, headers: {}, authenticated: true)
|
|
188
|
+
def post_multipart_model(path, model, fields: {}, files: {}, headers: {}, authenticated: true, operation: nil)
|
|
173
189
|
unless model <= T::Struct
|
|
174
190
|
raise TypeError, "response model for #{path} must inherit from T::Struct"
|
|
175
191
|
end
|
|
176
192
|
|
|
177
|
-
response = perform_multipart(path, fields, files, headers, authenticated, model)
|
|
193
|
+
response = perform_multipart(path, fields, files, headers, authenticated, model, operation)
|
|
178
194
|
return T.cast(response, T.type_parameter(:Model)) if response.is_a?(model)
|
|
179
195
|
|
|
180
196
|
raise TypeError, "expected #{model} from #{path}, got #{response.class}"
|
|
@@ -218,62 +234,76 @@ module Inttegro
|
|
|
218
234
|
files: Types::Payload,
|
|
219
235
|
headers: Types::Headers,
|
|
220
236
|
authenticated: T::Boolean,
|
|
221
|
-
model: T.nilable(T::Class[T::Struct])
|
|
237
|
+
model: T.nilable(T::Class[T::Struct]),
|
|
238
|
+
operation: T.nilable(String)
|
|
222
239
|
).returns(ResponseValue)
|
|
223
240
|
end
|
|
224
|
-
def perform_multipart(path, fields, files, headers, authenticated, model)
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
headers
|
|
233
|
-
|
|
234
|
-
|
|
241
|
+
def perform_multipart(path, fields, files, headers, authenticated, model, operation = nil)
|
|
242
|
+
@telemetry.in_span(path, :post, @base_url, Inttegro::VERSION, operation) do |span|
|
|
243
|
+
uri = build_uri(path, nil)
|
|
244
|
+
request = Net::HTTP::Post.new(uri)
|
|
245
|
+
request["Accept"] = "application/json"
|
|
246
|
+
request["User-Agent"] = USER_AGENT
|
|
247
|
+
request["Authorization"] = "Bearer #{@api_key}" if authenticated
|
|
248
|
+
headers = headers.dup
|
|
249
|
+
if authenticated && idempotent_mutation_path?(path) && !header_present?(headers, "Idempotency-Key")
|
|
250
|
+
headers["Idempotency-Key"] = generate_idempotency_key
|
|
251
|
+
end
|
|
252
|
+
headers.each { |key, value| request[key] = value }
|
|
235
253
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
254
|
+
form = []
|
|
255
|
+
fields.each do |key, value|
|
|
256
|
+
next if value.nil?
|
|
239
257
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
258
|
+
form << [key.to_s, value.is_a?(Hash) || value.is_a?(Array) ? JSON.generate(value) : value.to_s]
|
|
259
|
+
end
|
|
260
|
+
files.each do |key, file_path|
|
|
261
|
+
raise ArgumentError, "file path for #{key} must be a String" unless file_path.is_a?(String)
|
|
244
262
|
|
|
245
|
-
|
|
263
|
+
form << [key.to_s, File.open(file_path)]
|
|
264
|
+
end
|
|
265
|
+
request.set_form(form, "multipart/form-data")
|
|
266
|
+
@telemetry.prepare(span, request)
|
|
267
|
+
|
|
268
|
+
raw_response = @adapter ? @adapter.call(uri, request) : build_http(uri).request(request)
|
|
269
|
+
response = TransportResponse.new(raw_response)
|
|
270
|
+
@telemetry.response(span, response, decoded: false)
|
|
271
|
+
result = handle_response(path, response, model)
|
|
272
|
+
@telemetry.decoded(span)
|
|
273
|
+
result
|
|
246
274
|
end
|
|
247
|
-
request.set_form(form, "multipart/form-data")
|
|
248
|
-
|
|
249
|
-
raw_response = @adapter ? @adapter.call(uri, request) : build_http(uri).request(request)
|
|
250
|
-
response = TransportResponse.new(raw_response)
|
|
251
|
-
handle_response(path, response, model)
|
|
252
275
|
end
|
|
253
276
|
|
|
254
277
|
sig { params(path: String, body: Types::RequestBody).returns(FileDownload) }
|
|
255
278
|
def post_binary_json(path, body)
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
279
|
+
@telemetry.in_span(path, :post, @base_url, Inttegro::VERSION) do |span|
|
|
280
|
+
payload = with_request_meta_idempotency(:post, path, coerce_body(body), {})
|
|
281
|
+
response = raw_request(:post, path, JSON.dump(payload), {
|
|
282
|
+
"Accept" => "application/octet-stream",
|
|
283
|
+
"Content-Type" => "application/json",
|
|
284
|
+
"Authorization" => "Bearer #{@api_key}"
|
|
285
|
+
}, span)
|
|
286
|
+
@telemetry.response(span, response, decoded: false)
|
|
287
|
+
return FileDownload.new(response.body, response.headers) if response.code.to_i < 400
|
|
288
|
+
|
|
289
|
+
raise_response_error(response)
|
|
290
|
+
end
|
|
265
291
|
end
|
|
266
292
|
|
|
267
293
|
sig { params(url: String).returns(FileDownload) }
|
|
268
294
|
def get_binary_public(url)
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
295
|
+
@telemetry.in_span(url, :get, @base_url, Inttegro::VERSION, "file_links.download") do |span|
|
|
296
|
+
uri = build_uri(url, nil)
|
|
297
|
+
request = Net::HTTP::Get.new(uri)
|
|
298
|
+
request["User-Agent"] = USER_AGENT
|
|
299
|
+
@telemetry.prepare(span, request)
|
|
300
|
+
raw_response = @adapter ? @adapter.call(uri, request) : build_http(uri).request(request)
|
|
301
|
+
response = TransportResponse.new(raw_response)
|
|
302
|
+
@telemetry.response(span, response, decoded: false)
|
|
303
|
+
return FileDownload.new(response.body, response.headers) if response.code.to_i < 400
|
|
304
|
+
|
|
305
|
+
raise_response_error(response)
|
|
306
|
+
end
|
|
277
307
|
end
|
|
278
308
|
|
|
279
309
|
sig do
|
|
@@ -287,20 +317,26 @@ module Inttegro
|
|
|
287
317
|
).returns(ResponseValue)
|
|
288
318
|
end
|
|
289
319
|
def request(method, path, body: nil, headers: {}, query: nil, response_model: nil)
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
320
|
+
@telemetry.in_span(path, method, @base_url, Inttegro::VERSION) do |span|
|
|
321
|
+
uri = build_uri(path, query)
|
|
322
|
+
body = validate_body(path, coerce_body(body))
|
|
323
|
+
body = with_request_meta_idempotency(method, path, body, headers)
|
|
324
|
+
request = build_request(method, uri, body, headers)
|
|
325
|
+
@telemetry.prepare(span, request)
|
|
326
|
+
|
|
327
|
+
raw_response =
|
|
328
|
+
if @adapter
|
|
329
|
+
@adapter.call(uri, request)
|
|
330
|
+
else
|
|
331
|
+
http = build_http(uri)
|
|
332
|
+
http.request(request)
|
|
333
|
+
end
|
|
334
|
+
response = TransportResponse.new(raw_response)
|
|
335
|
+
@telemetry.response(span, response, decoded: false)
|
|
336
|
+
result = handle_response(path, response, response_model)
|
|
337
|
+
@telemetry.decoded(span)
|
|
338
|
+
result
|
|
339
|
+
end
|
|
304
340
|
rescue Timeout::Error, Errno::ETIMEDOUT => e
|
|
305
341
|
raise TimeoutError.new("Request timed out", e)
|
|
306
342
|
rescue SocketError, Errno::ECONNREFUSED, Errno::ECONNRESET => e
|
|
@@ -327,13 +363,15 @@ module Inttegro
|
|
|
327
363
|
method: T.any(String, Symbol),
|
|
328
364
|
path: String,
|
|
329
365
|
body: T.nilable(String),
|
|
330
|
-
headers: Types::Headers
|
|
366
|
+
headers: Types::Headers,
|
|
367
|
+
span: T.nilable(OpenTelemetry::Trace::Span)
|
|
331
368
|
).returns(TransportResponse)
|
|
332
369
|
end
|
|
333
|
-
def raw_request(method, path, body, headers)
|
|
370
|
+
def raw_request(method, path, body, headers, span = nil)
|
|
334
371
|
uri = build_uri(path, nil)
|
|
335
372
|
request = build_request(method, uri, nil, headers)
|
|
336
373
|
request.body = body if body
|
|
374
|
+
@telemetry.prepare(span, request)
|
|
337
375
|
raw_response = @adapter ? @adapter.call(uri, request) : build_http(uri).request(request)
|
|
338
376
|
TransportResponse.new(raw_response)
|
|
339
377
|
end
|
data/lib/inttegro/models.rb
CHANGED
|
@@ -9,6 +9,58 @@ require_relative "types"
|
|
|
9
9
|
module Inttegro
|
|
10
10
|
extend T::Sig
|
|
11
11
|
|
|
12
|
+
# Amount primitives live under Money so the namespace can grow to include
|
|
13
|
+
# currency conversion and formatting helpers without treating money as a
|
|
14
|
+
# single value type.
|
|
15
|
+
module Money
|
|
16
|
+
Amount = Inttegro::Amount
|
|
17
|
+
AmountParams = Inttegro::AmountParams
|
|
18
|
+
Currency = Inttegro::Currency
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Wallet variants used by financial accounts.
|
|
22
|
+
module Wallets
|
|
23
|
+
Wallet = Inttegro::FinancialAccountWallet
|
|
24
|
+
MobileMoney = Inttegro::FinancialAccountWalletMobileMoney
|
|
25
|
+
UpdatedWallet = Inttegro::UpdatedFinancialAccountWallet
|
|
26
|
+
WalletParams = Inttegro::FinancialAccountWalletRequestWallet
|
|
27
|
+
MobileMoneyParams = Inttegro::FinancialAccountWalletRequestWalletMobileMoney
|
|
28
|
+
WalletType = Inttegro::WalletType
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Bank-account variants used by financial accounts. Payment-method bank
|
|
32
|
+
# snapshots remain in the payment-method domain.
|
|
33
|
+
module BankAccounts
|
|
34
|
+
BankAccount = Inttegro::FinancialAccountBank
|
|
35
|
+
CreatedBankAccount = Inttegro::CreatedFinancialAccountBank
|
|
36
|
+
UpdatedBankAccount = Inttegro::UpdatedFinancialAccountBank
|
|
37
|
+
GhanaBankAccount = Inttegro::GhanaBankAccount
|
|
38
|
+
CreatedGhanaBankAccount = Inttegro::CreatedGhanaBankAccount
|
|
39
|
+
UpdatedGhanaBankAccount = Inttegro::UpdatedGhanaBankAccount
|
|
40
|
+
Owner = Inttegro::FinancialAccountOwner
|
|
41
|
+
CreatedOwner = Inttegro::CreatedFinancialAccountOwner
|
|
42
|
+
UpdatedOwner = Inttegro::UpdatedFinancialAccountOwner
|
|
43
|
+
OwnerAddress = Inttegro::FinancialAccountAddress
|
|
44
|
+
CreatedOwnerAddress = Inttegro::CreatedFinancialAccountAddress
|
|
45
|
+
UpdatedOwnerAddress = Inttegro::UpdatedFinancialAccountAddress
|
|
46
|
+
BankAccountParams = Inttegro::FinancialAccountBankRequestBankAccount
|
|
47
|
+
GhanaBankAccountParams = Inttegro::FinancialAccountBankRequestBankAccountGhanaBankAccount
|
|
48
|
+
BankAccountType = Inttegro::BankAccountType
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Currency identifiers serialize to lowercase wire values while accepting
|
|
52
|
+
# legacy uppercase response values during deserialization.
|
|
53
|
+
class Currency
|
|
54
|
+
class << self
|
|
55
|
+
extend T::Sig
|
|
56
|
+
|
|
57
|
+
sig { params(value: String).returns(Inttegro::Currency) }
|
|
58
|
+
def deserialize(value)
|
|
59
|
+
super(value.strip.downcase)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
12
64
|
# Backward-compatible acronym spellings for domain objects.
|
|
13
65
|
OtpTransaction = OTPTransaction
|
|
14
66
|
OtpTransmission = OTPTransmission
|
|
@@ -9,11 +9,11 @@ module Inttegro
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def create(payload)
|
|
12
|
-
@http.post_resource("/prices/create", Inttegro::
|
|
12
|
+
@http.post_resource("/prices/create", Inttegro::CatalogPrice, :price, payload)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def lookup(price_id:)
|
|
16
|
-
@http.post_resource("/prices/lookup", Inttegro::
|
|
16
|
+
@http.post_resource("/prices/lookup", Inttegro::CatalogPrice, :price, { price_id: price_id })
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def page(payload = {})
|
|
@@ -21,19 +21,19 @@ module Inttegro
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def update(payload)
|
|
24
|
-
@http.post_resource("/prices/update", Inttegro::
|
|
24
|
+
@http.post_resource("/prices/update", Inttegro::CatalogPrice, :price, payload)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
def activate(price_id:)
|
|
28
|
-
@http.post_resource("/prices/activate", Inttegro::
|
|
28
|
+
@http.post_resource("/prices/activate", Inttegro::CatalogPrice, :price, { price_id: price_id })
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def deactivate(price_id:)
|
|
32
|
-
@http.post_resource("/prices/deactivate", Inttegro::
|
|
32
|
+
@http.post_resource("/prices/deactivate", Inttegro::CatalogPrice, :price, { price_id: price_id })
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def archive(price_id:)
|
|
36
|
-
@http.post_resource("/prices/archive", Inttegro::
|
|
36
|
+
@http.post_resource("/prices/archive", Inttegro::CatalogPrice, :price, { price_id: price_id })
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
39
|
end
|
|
@@ -13,7 +13,7 @@ module Inttegro
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def add_price(payload)
|
|
16
|
-
@http.post_resource("/products/add_price", Inttegro::
|
|
16
|
+
@http.post_resource("/products/add_price", Inttegro::CatalogPrice, :price, payload)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def set_default_unit_price(payload)
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# typed: strict
|
|
3
|
+
|
|
4
|
+
require "opentelemetry-api"
|
|
5
|
+
require "sorbet-runtime"
|
|
6
|
+
require "uri"
|
|
7
|
+
|
|
8
|
+
require_relative "errors"
|
|
9
|
+
|
|
10
|
+
module Inttegro
|
|
11
|
+
# Emits redacted SDK spans to the application's OpenTelemetry provider.
|
|
12
|
+
# This class never configures an exporter or sends telemetry to Inttegro.
|
|
13
|
+
class Telemetry
|
|
14
|
+
extend T::Sig
|
|
15
|
+
|
|
16
|
+
SAFE_RESOURCES = %w[
|
|
17
|
+
apps balance_transactions balances broadcasts checkout chimes customers file_links file_references files
|
|
18
|
+
financial_accounts keys message_templates orders otp payment_methods payouts ping prices products
|
|
19
|
+
purchase_intents refunds schedules sessions spec upload_requests
|
|
20
|
+
].freeze
|
|
21
|
+
SAFE_ACTIONS = %w[
|
|
22
|
+
activate add_price archive broadcast cancel complete confirm_payment confirm_verification connect contents
|
|
23
|
+
countries create deactivate delete destroy disable disable_fx disable_pull disable_push disactivate disconnect
|
|
24
|
+
enable enable_fx enable_pull enable_push finalize generate initiate lookup new open page pay publish reconcile
|
|
25
|
+
reconnect refund render_preview request_confirmation review revoke schedule send send_invoice send_receipt
|
|
26
|
+
set_default_unit_price set_destinations settings tokenize unarchive unpublish update upload usage verify
|
|
27
|
+
].freeze
|
|
28
|
+
|
|
29
|
+
sig do
|
|
30
|
+
params(
|
|
31
|
+
version: String,
|
|
32
|
+
enabled: T::Boolean,
|
|
33
|
+
tracer_provider: T.nilable(OpenTelemetry::Trace::TracerProvider)
|
|
34
|
+
).void
|
|
35
|
+
end
|
|
36
|
+
def initialize(version, enabled: true, tracer_provider: nil)
|
|
37
|
+
@enabled = T.let(enabled, T::Boolean)
|
|
38
|
+
provider = tracer_provider || OpenTelemetry.tracer_provider
|
|
39
|
+
@tracer = T.let(provider.tracer("inttegro", version), OpenTelemetry::Trace::Tracer)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
sig do
|
|
43
|
+
type_parameters(:Result)
|
|
44
|
+
.params(
|
|
45
|
+
path_or_url: String,
|
|
46
|
+
method: T.any(String, Symbol),
|
|
47
|
+
base_url: String,
|
|
48
|
+
version: String,
|
|
49
|
+
operation_override: T.nilable(String),
|
|
50
|
+
block: T.proc.params(span: T.nilable(OpenTelemetry::Trace::Span)).returns(T.type_parameter(:Result))
|
|
51
|
+
)
|
|
52
|
+
.returns(T.type_parameter(:Result))
|
|
53
|
+
end
|
|
54
|
+
def in_span(path_or_url, method, base_url, version, operation_override = nil, &block)
|
|
55
|
+
return yield(nil) unless @enabled
|
|
56
|
+
|
|
57
|
+
operation, route, server_address = request_details(path_or_url, base_url, operation_override)
|
|
58
|
+
attributes = {
|
|
59
|
+
"inttegro.operation.name" => operation,
|
|
60
|
+
"inttegro.sdk.language" => "ruby",
|
|
61
|
+
"inttegro.sdk.version" => version,
|
|
62
|
+
"http.request.method" => method.to_s.upcase,
|
|
63
|
+
"server.address" => server_address
|
|
64
|
+
}
|
|
65
|
+
attributes["url.template"] = route if route
|
|
66
|
+
span = @tracer.start_span("inttegro.#{operation}", kind: :client, attributes: attributes)
|
|
67
|
+
|
|
68
|
+
begin
|
|
69
|
+
OpenTelemetry::Trace.with_span(span) { |_active_span, _context| yield(span) }
|
|
70
|
+
rescue StandardError => e
|
|
71
|
+
error_type = classify_error(e)
|
|
72
|
+
span.set_attribute("error.type", error_type)
|
|
73
|
+
span.status = OpenTelemetry::Trace::Status.error
|
|
74
|
+
span.add_event("inttegro.request.failed", attributes: { "error.type" => error_type })
|
|
75
|
+
raise
|
|
76
|
+
ensure
|
|
77
|
+
span.finish
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
sig { params(span: T.nilable(OpenTelemetry::Trace::Span), request: Net::HTTPRequest).void }
|
|
82
|
+
def prepare(span, request)
|
|
83
|
+
if @enabled
|
|
84
|
+
carrier = T.let({}, T::Hash[String, String])
|
|
85
|
+
OpenTelemetry.propagation.inject(carrier)
|
|
86
|
+
carrier.each { |key, value| request[key] = value unless request[key] }
|
|
87
|
+
end
|
|
88
|
+
return unless span
|
|
89
|
+
|
|
90
|
+
span.add_event("inttegro.request.prepared")
|
|
91
|
+
span.add_event(
|
|
92
|
+
"inttegro.http.attempt.started",
|
|
93
|
+
attributes: { "http.request.resend_count" => 0 }
|
|
94
|
+
)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
sig do
|
|
98
|
+
params(
|
|
99
|
+
span: T.nilable(OpenTelemetry::Trace::Span),
|
|
100
|
+
response: TransportResponse,
|
|
101
|
+
decoded: T::Boolean
|
|
102
|
+
).void
|
|
103
|
+
end
|
|
104
|
+
def response(span, response, decoded:)
|
|
105
|
+
return unless span
|
|
106
|
+
|
|
107
|
+
status = response.code.to_i
|
|
108
|
+
span.set_attribute("http.response.status_code", status)
|
|
109
|
+
request_id = response["x-request-id"]
|
|
110
|
+
span.set_attribute("inttegro.request.id", request_id) if request_id && !request_id.empty?
|
|
111
|
+
span.add_event(
|
|
112
|
+
"inttegro.response.received",
|
|
113
|
+
attributes: {
|
|
114
|
+
"http.response.status_code" => status,
|
|
115
|
+
"http.request.resend_count" => 0
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
span.add_event("inttegro.response.decoded") if decoded
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
sig { params(span: T.nilable(OpenTelemetry::Trace::Span)).void }
|
|
122
|
+
def decoded(span)
|
|
123
|
+
span.add_event("inttegro.response.decoded") if span
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
private
|
|
127
|
+
|
|
128
|
+
sig do
|
|
129
|
+
params(path_or_url: String, base_url: String, override: T.nilable(String))
|
|
130
|
+
.returns([String, T.nilable(String), String])
|
|
131
|
+
end
|
|
132
|
+
def request_details(path_or_url, base_url, override)
|
|
133
|
+
uri = path_or_url.start_with?("http://", "https://") ? URI.parse(path_or_url) : URI.join("#{base_url}/", path_or_url.sub(%r{\A/}, ""))
|
|
134
|
+
segments = path_or_url.start_with?("http://", "https://") ? [] : T.must(uri.path).split("/").reject(&:empty?)
|
|
135
|
+
resource = segments[0]
|
|
136
|
+
action = segments[1]
|
|
137
|
+
known_route = !resource.nil? && segments.length <= 2 && SAFE_RESOURCES.include?(resource) &&
|
|
138
|
+
(action.nil? || SAFE_ACTIONS.include?(action))
|
|
139
|
+
route = known_route ? uri.path : nil
|
|
140
|
+
derived_operation = known_route ? "#{resource}.#{action || (resource == 'balances' ? 'lookup' : 'request')}" : "http.request"
|
|
141
|
+
[override || derived_operation, route, uri.host || "unknown"]
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
sig { params(error: StandardError).returns(String) }
|
|
145
|
+
def classify_error(error)
|
|
146
|
+
return "timeout" if error.is_a?(TimeoutError) || error.is_a?(Timeout::Error) || error.is_a?(Errno::ETIMEDOUT)
|
|
147
|
+
return "network_error" if error.is_a?(NetworkError) || error.is_a?(SocketError) || error.is_a?(SystemCallError)
|
|
148
|
+
return "http_#{error.status}" if error.is_a?(APIError)
|
|
149
|
+
return "decode_error" if error.is_a?(JSON::ParserError)
|
|
150
|
+
|
|
151
|
+
"unknown_error"
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
private_constant :Telemetry
|
|
156
|
+
end
|
data/lib/inttegro/version.rb
CHANGED
data/rbi/inttegro/generated.rbi
CHANGED
|
@@ -388,25 +388,25 @@ module Inttegro
|
|
|
388
388
|
sig { params(http: Inttegro::HTTPClient).void }
|
|
389
389
|
def initialize(http); end
|
|
390
390
|
|
|
391
|
-
sig { params(price_id: String).returns(Inttegro::
|
|
391
|
+
sig { params(price_id: String).returns(Inttegro::CatalogPrice) }
|
|
392
392
|
def activate(price_id:); end
|
|
393
393
|
|
|
394
|
-
sig { params(price_id: String).returns(Inttegro::
|
|
394
|
+
sig { params(price_id: String).returns(Inttegro::CatalogPrice) }
|
|
395
395
|
def archive(price_id:); end
|
|
396
396
|
|
|
397
|
-
sig { params(payload: T.any(Inttegro::
|
|
397
|
+
sig { params(payload: T.any(Inttegro::CatalogPriceParams, Inttegro::Types::Payload)).returns(Inttegro::CatalogPrice) }
|
|
398
398
|
def create(payload); end
|
|
399
399
|
|
|
400
|
-
sig { params(price_id: String).returns(Inttegro::
|
|
400
|
+
sig { params(price_id: String).returns(Inttegro::CatalogPrice) }
|
|
401
401
|
def deactivate(price_id:); end
|
|
402
402
|
|
|
403
|
-
sig { params(price_id: String).returns(Inttegro::
|
|
403
|
+
sig { params(price_id: String).returns(Inttegro::CatalogPrice) }
|
|
404
404
|
def lookup(price_id:); end
|
|
405
405
|
|
|
406
406
|
sig { params(payload: T.nilable(T.any(Inttegro::PricePageRequest, Inttegro::Types::Payload))).returns(Inttegro::PricePage) }
|
|
407
407
|
def page(payload = nil); end
|
|
408
408
|
|
|
409
|
-
sig { params(payload: T.any(Inttegro::UpdatePriceRequest, Inttegro::Types::Payload)).returns(Inttegro::
|
|
409
|
+
sig { params(payload: T.any(Inttegro::UpdatePriceRequest, Inttegro::Types::Payload)).returns(Inttegro::CatalogPrice) }
|
|
410
410
|
def update(payload); end
|
|
411
411
|
end
|
|
412
412
|
|
|
@@ -414,7 +414,7 @@ module Inttegro
|
|
|
414
414
|
sig { params(http: Inttegro::HTTPClient).void }
|
|
415
415
|
def initialize(http); end
|
|
416
416
|
|
|
417
|
-
sig { params(payload: T.any(Inttegro::AddProductPriceRequest, Inttegro::Types::Payload)).returns(Inttegro::
|
|
417
|
+
sig { params(payload: T.any(Inttegro::AddProductPriceRequest, Inttegro::Types::Payload)).returns(Inttegro::CatalogPrice) }
|
|
418
418
|
def add_price(payload); end
|
|
419
419
|
|
|
420
420
|
sig { params(product_id: String).returns(Inttegro::Product) }
|