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.
@@ -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::CreatePriceRequest",
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",
@@ -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(api_key:, base_url: DEFAULT_BASE_URL, read_timeout: 30, open_timeout: 10, adapter: nil)
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
- uri = build_uri(path, nil)
226
- request = Net::HTTP::Post.new(uri)
227
- request["Accept"] = "application/json"
228
- request["User-Agent"] = USER_AGENT
229
- request["Authorization"] = "Bearer #{@api_key}" if authenticated
230
- headers = headers.dup
231
- if authenticated && idempotent_mutation_path?(path) && !header_present?(headers, "Idempotency-Key")
232
- headers["Idempotency-Key"] = generate_idempotency_key
233
- end
234
- headers.each { |key, value| request[key] = value }
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
- form = []
237
- fields.each do |key, value|
238
- next if value.nil?
254
+ form = []
255
+ fields.each do |key, value|
256
+ next if value.nil?
239
257
 
240
- form << [key.to_s, value.is_a?(Hash) || value.is_a?(Array) ? JSON.generate(value) : value.to_s]
241
- end
242
- files.each do |key, path|
243
- raise ArgumentError, "file path for #{key} must be a String" unless path.is_a?(String)
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
- form << [key.to_s, File.open(path)]
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
- body = with_request_meta_idempotency(:post, path, coerce_body(body), {})
257
- response = raw_request(:post, path, JSON.dump(body), {
258
- "Accept" => "application/octet-stream",
259
- "Content-Type" => "application/json",
260
- "Authorization" => "Bearer #{@api_key}"
261
- })
262
- return FileDownload.new(response.body, response.headers) if response.code.to_i < 400
263
-
264
- raise_response_error(response)
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
- uri = build_uri(url, nil)
270
- request = Net::HTTP::Get.new(uri)
271
- request["User-Agent"] = USER_AGENT
272
- raw_response = @adapter ? @adapter.call(uri, request) : build_http(uri).request(request)
273
- response = TransportResponse.new(raw_response)
274
- return FileDownload.new(response.body, response.headers) if response.code.to_i < 400
275
-
276
- raise_response_error(response)
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
- uri = build_uri(path, query)
291
- body = validate_body(path, coerce_body(body))
292
- body = with_request_meta_idempotency(method, path, body, headers)
293
- request = build_request(method, uri, body, headers)
294
-
295
- raw_response =
296
- if @adapter
297
- @adapter.call(uri, request)
298
- else
299
- http = build_http(uri)
300
- http.request(request)
301
- end
302
- response = TransportResponse.new(raw_response)
303
- handle_response(path, response, response_model)
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
@@ -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
@@ -203,7 +203,7 @@ module Inttegro
203
203
  # token: '123456'
204
204
  # )
205
205
  #
206
- # if order.payment&.status == Inttegro::OrderPaymentStatus::PAID
206
+ # if order.payment&.status == Inttegro::PaymentStatus::PAID
207
207
  # puts 'Payment confirmed successfully!'
208
208
  # end
209
209
  #
@@ -9,11 +9,11 @@ module Inttegro
9
9
  end
10
10
 
11
11
  def create(payload)
12
- @http.post_resource("/prices/create", Inttegro::Price, :price, payload)
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::Price, :price, { price_id: price_id })
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::Price, :price, payload)
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::Price, :price, { price_id: price_id })
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::Price, :price, { price_id: price_id })
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::Price, :price, { price_id: price_id })
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::ProductPriceNominal, :price, payload)
16
+ @http.post_resource("/products/add_price", Inttegro::CatalogPrice, :price, payload)
17
17
  end
18
18
 
19
19
  def set_default_unit_price(payload)
@@ -52,7 +52,8 @@ module Inttegro
52
52
  upload_url,
53
53
  Inttegro::UploadFulfillment,
54
54
  files: { file: file },
55
- authenticated: false
55
+ authenticated: false,
56
+ operation: "upload_requests.upload"
56
57
  )
57
58
  end
58
59
 
@@ -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
@@ -2,5 +2,5 @@
2
2
  # typed: strict
3
3
 
4
4
  module Inttegro
5
- VERSION = "3.0.1"
5
+ VERSION = "4.2.1"
6
6
  end
@@ -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::Price) }
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::Price) }
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::CreatePriceRequest, Inttegro::Types::Payload)).returns(Inttegro::Price) }
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::Price) }
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::Price) }
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::Price) }
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::ProductPriceNominal) }
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) }