schematichq 1.5.3 → 1.5.4

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 (220) hide show
  1. checksums.yaml +4 -4
  2. data/.fern/metadata.json +4 -4
  3. data/.fern/replay.lock +7 -1
  4. data/.fernignore +2 -0
  5. data/.rubocop.yml +4 -0
  6. data/README.md +1 -1
  7. data/WASM_VERSION +1 -1
  8. data/lib/schematic/accesstokens/client.rb +9 -1
  9. data/lib/schematic/accounts/client.rb +183 -21
  10. data/lib/schematic/billing/client.rb +325 -34
  11. data/lib/schematic/billing/types/create_billing_price_request_body.rb +1 -1
  12. data/lib/schematic/billing/types/create_billing_product_request_body.rb +1 -1
  13. data/lib/schematic/billing/types/create_billing_subscription_request_body.rb +1 -1
  14. data/lib/schematic/billing/types/create_coupon_request_body.rb +2 -2
  15. data/lib/schematic/billing/types/create_invoice_request_body.rb +1 -1
  16. data/lib/schematic/billing/types/get_billing_settings_response.rb +13 -0
  17. data/lib/schematic/billing/types/list_billing_prices_params.rb +1 -1
  18. data/lib/schematic/billing/types/list_billing_prices_request.rb +1 -1
  19. data/lib/schematic/billing/types/list_billing_product_prices_params.rb +1 -1
  20. data/lib/schematic/billing/types/list_billing_product_prices_request.rb +1 -1
  21. data/lib/schematic/billing/types/update_billing_settings_request_body.rb +11 -0
  22. data/lib/schematic/billing/types/update_billing_settings_response.rb +13 -0
  23. data/lib/schematic/catalogs/client.rb +121 -14
  24. data/lib/schematic/checkout/client.rb +80 -9
  25. data/lib/schematic/checkout/types/checkout_data_request_body.rb +1 -1
  26. data/lib/schematic/client.rb +5 -3
  27. data/lib/schematic/companies/client.rb +380 -44
  28. data/lib/schematic/components/client.rb +70 -8
  29. data/lib/schematic/components/types/create_component_request_body.rb +1 -1
  30. data/lib/schematic/components/types/update_component_request_body.rb +1 -1
  31. data/lib/schematic/componentspublic/client.rb +8 -1
  32. data/lib/schematic/credits/client.rb +409 -41
  33. data/lib/schematic/credits/types/acquire_credit_lease_request_body.rb +1 -1
  34. data/lib/schematic/credits/types/create_billing_credit_request_body.rb +1 -1
  35. data/lib/schematic/credits/types/create_company_credit_grant.rb +1 -1
  36. data/lib/schematic/credits/types/create_credit_bundle_request_body.rb +1 -1
  37. data/lib/schematic/credits/types/create_credit_spend_policy_request_body.rb +2 -2
  38. data/lib/schematic/credits/types/extend_credit_lease_request_body.rb +1 -1
  39. data/lib/schematic/credits/types/get_credit_balance_time_series_params.rb +18 -0
  40. data/lib/schematic/credits/types/get_credit_balance_time_series_request.rb +17 -0
  41. data/lib/schematic/credits/types/get_credit_balance_time_series_response.rb +13 -0
  42. data/lib/schematic/credits/types/reserve_credits_request_body.rb +1 -1
  43. data/lib/schematic/credits/types/update_credit_spend_policy_request_body.rb +2 -2
  44. data/lib/schematic/dataexports/client.rb +36 -6
  45. data/lib/schematic/entitlements/client.rb +244 -28
  46. data/lib/schematic/entitlements/types/create_billing_linked_plan_entitlement_request_body.rb +4 -2
  47. data/lib/schematic/entitlements/types/create_company_override_request_body.rb +3 -1
  48. data/lib/schematic/entitlements/types/create_plan_entitlement_request_body.rb +4 -2
  49. data/lib/schematic/entitlements/types/update_company_override_request_body.rb +3 -1
  50. data/lib/schematic/entitlements/types/update_plan_entitlement_request_body.rb +4 -2
  51. data/lib/schematic/errors/connection_error.rb +11 -0
  52. data/lib/schematic/errors/response_error.rb +23 -2
  53. data/lib/schematic/events/client.rb +78 -9
  54. data/lib/schematic/features/client.rb +160 -18
  55. data/lib/schematic/features/types/check_and_reserve_flag_request_body.rb +1 -1
  56. data/lib/schematic/features/types/create_billing_linked_feature_request_body.rb +2 -0
  57. data/lib/schematic/features/types/create_feature_request_body.rb +2 -0
  58. data/lib/schematic/features/types/update_feature_request_body.rb +2 -0
  59. data/lib/schematic/insights/client.rb +48 -6
  60. data/lib/schematic/integrationsapi/client.rb +120 -14
  61. data/lib/schematic/internal/http/base_request.rb +30 -0
  62. data/lib/schematic/internal/http/raw_client.rb +35 -5
  63. data/lib/schematic/internal/iterators/cursor_item_iterator.rb +7 -2
  64. data/lib/schematic/internal/iterators/cursor_page_iterator.rb +68 -14
  65. data/lib/schematic/internal/iterators/item_iterator.rb +61 -15
  66. data/lib/schematic/internal/iterators/offset_item_iterator.rb +7 -2
  67. data/lib/schematic/internal/iterators/offset_page_iterator.rb +57 -9
  68. data/lib/schematic/internal/json/request.rb +11 -2
  69. data/lib/schematic/internal/multipart/multipart_request.rb +1 -0
  70. data/lib/schematic/internal/types/model.rb +7 -3
  71. data/lib/schematic/internal/types/utils.rb +7 -0
  72. data/lib/schematic/licenses/client.rb +26 -3
  73. data/lib/schematic/planbundle/client.rb +27 -3
  74. data/lib/schematic/plangroups/client.rb +26 -3
  75. data/lib/schematic/planmigrations/client.rb +98 -11
  76. data/lib/schematic/plans/client.rb +213 -23
  77. data/lib/schematic/plans/types/get_plan_version_diff_params.rb +12 -0
  78. data/lib/schematic/plans/types/get_plan_version_diff_request.rb +13 -0
  79. data/lib/schematic/plans/types/get_plan_version_diff_response.rb +13 -0
  80. data/lib/schematic/plans/types/publish_plan_version_request_body.rb +2 -0
  81. data/lib/schematic/rules_engine.rb +14 -2
  82. data/lib/schematic/scheduledcheckout/client.rb +35 -4
  83. data/lib/schematic/schematic_client.rb +22 -11
  84. data/lib/schematic/types/billing_coupon_response_data.rb +2 -2
  85. data/lib/schematic/types/billing_credit_grant_response_data.rb +8 -8
  86. data/lib/schematic/types/billing_customer_subscription.rb +1 -1
  87. data/lib/schematic/types/billing_plan_credit_grant_response_data.rb +1 -1
  88. data/lib/schematic/types/billing_price_response_data.rb +1 -1
  89. data/lib/schematic/types/billing_price_view.rb +1 -1
  90. data/lib/schematic/types/billing_product_detail_response_data.rb +2 -2
  91. data/lib/schematic/types/billing_product_for_subscription_response_data.rb +2 -2
  92. data/lib/schematic/types/billing_product_price_response_data.rb +1 -1
  93. data/lib/schematic/types/billing_product_pricing.rb +1 -1
  94. data/lib/schematic/types/billing_product_response_data.rb +2 -2
  95. data/lib/schematic/types/billing_settings_response_data.rb +9 -0
  96. data/lib/schematic/types/billing_subscription_discount_view.rb +2 -2
  97. data/lib/schematic/types/billing_subscription_response_data.rb +1 -1
  98. data/lib/schematic/types/billing_subscription_view.rb +1 -1
  99. data/lib/schematic/types/catalog_config_ordered_plan.rb +2 -0
  100. data/lib/schematic/types/catalog_config_ordered_plan_response_data.rb +2 -0
  101. data/lib/schematic/types/catalog_config_plan_credit.rb +11 -0
  102. data/lib/schematic/types/catalog_config_plan_credit_response_data.rb +11 -0
  103. data/lib/schematic/types/change_subscription_internal_request_body.rb +1 -1
  104. data/lib/schematic/types/change_subscription_request_body.rb +1 -1
  105. data/lib/schematic/types/checkout_problem_code.rb +54 -0
  106. data/lib/schematic/types/checkout_problem_response_data.rb +31 -0
  107. data/lib/schematic/types/checkout_problem_source.rb +13 -0
  108. data/lib/schematic/types/checkout_subscription.rb +1 -1
  109. data/lib/schematic/types/company_billing_entity_subscription_response_data.rb +1 -1
  110. data/lib/schematic/types/company_credit_balance.rb +3 -3
  111. data/lib/schematic/types/company_credit_balance_response_data.rb +4 -4
  112. data/lib/schematic/types/company_detail_response_data.rb +1 -1
  113. data/lib/schematic/types/company_override_response_data.rb +3 -1
  114. data/lib/schematic/types/company_plan_credit_grant_view.rb +1 -1
  115. data/lib/schematic/types/company_plan_detail_response_data.rb +2 -0
  116. data/lib/schematic/types/company_subscription_response_data.rb +1 -1
  117. data/lib/schematic/types/company_user_usage_response_data.rb +2 -2
  118. data/lib/schematic/types/company_user_usage_row_response_data.rb +2 -2
  119. data/lib/schematic/types/component_response_data.rb +1 -1
  120. data/lib/schematic/types/condition.rb +3 -1
  121. data/lib/schematic/types/condition_response_data.rb +3 -1
  122. data/lib/schematic/types/condition_view.rb +3 -1
  123. data/lib/schematic/types/coupon_request_body.rb +2 -2
  124. data/lib/schematic/types/create_billing_plan_credit_grant_request_body.rb +1 -1
  125. data/lib/schematic/types/create_entitlement_in_bundle_request_body.rb +4 -2
  126. data/lib/schematic/types/create_entitlement_req_common.rb +3 -1
  127. data/lib/schematic/types/create_or_update_condition_request_body.rb +1 -1
  128. data/lib/schematic/types/credit_balance_event_response_data.rb +21 -0
  129. data/lib/schematic/types/credit_balance_feature_consumption_response_data.rb +13 -0
  130. data/lib/schematic/types/credit_balance_point_response_data.rb +15 -0
  131. data/lib/schematic/types/credit_balance_time_series_response_data.rb +15 -0
  132. data/lib/schematic/types/credit_bundle_currency_price.rb +1 -1
  133. data/lib/schematic/types/credit_bundle_currency_price_request_body.rb +1 -1
  134. data/lib/schematic/types/credit_bundle_currency_price_response_data.rb +1 -1
  135. data/lib/schematic/types/credit_burn_breakdown_line.rb +15 -0
  136. data/lib/schematic/types/credit_company_grant_view.rb +8 -8
  137. data/lib/schematic/types/credit_currency_price.rb +1 -1
  138. data/lib/schematic/types/credit_currency_price_request_body.rb +1 -1
  139. data/lib/schematic/types/credit_currency_price_response_data.rb +1 -1
  140. data/lib/schematic/types/credit_event_ledger_response_data.rb +10 -6
  141. data/lib/schematic/types/credit_grant_detail.rb +1 -1
  142. data/lib/schematic/types/credit_lease_response_data.rb +2 -2
  143. data/lib/schematic/types/credit_reservation_response_data.rb +2 -2
  144. data/lib/schematic/types/credit_spend_policy.rb +2 -2
  145. data/lib/schematic/types/credit_spend_policy_response_data.rb +4 -4
  146. data/lib/schematic/types/credit_transfer_response_data.rb +1 -1
  147. data/lib/schematic/types/credit_transfer_view.rb +1 -1
  148. data/lib/schematic/types/credit_usage.rb +5 -5
  149. data/lib/schematic/types/credit_usage_aggregation.rb +4 -4
  150. data/lib/schematic/types/credit_usage_reason.rb +1 -0
  151. data/lib/schematic/types/credits_in_plan.rb +11 -0
  152. data/lib/schematic/types/currency.rb +144 -0
  153. data/lib/schematic/types/currency_price_request_body.rb +1 -1
  154. data/lib/schematic/types/custom_plan_billing_response_data.rb +6 -0
  155. data/lib/schematic/types/entitlement_currency_prices_response_data.rb +1 -1
  156. data/lib/schematic/types/estimated_plan_total.rb +1 -1
  157. data/lib/schematic/types/feature_company_response_data.rb +7 -7
  158. data/lib/schematic/types/feature_detail_response_data.rb +2 -0
  159. data/lib/schematic/types/feature_entitlement.rb +8 -6
  160. data/lib/schematic/types/feature_event_source.rb +12 -0
  161. data/lib/schematic/types/feature_in_plan_response_data.rb +2 -0
  162. data/lib/schematic/types/feature_response_data.rb +2 -0
  163. data/lib/schematic/types/feature_usage_response_data.rb +7 -7
  164. data/lib/schematic/types/feature_view.rb +2 -0
  165. data/lib/schematic/types/flag_check_reservation_response_data.rb +3 -3
  166. data/lib/schematic/types/insights_summary_response_data.rb +1 -1
  167. data/lib/schematic/types/invoice_request_body.rb +1 -1
  168. data/lib/schematic/types/invoice_response_data.rb +1 -1
  169. data/lib/schematic/types/manage_plan_preview_response_response_data.rb +2 -0
  170. data/lib/schematic/types/manage_plan_request.rb +3 -1
  171. data/lib/schematic/types/manage_plan_response_response_data.rb +4 -0
  172. data/lib/schematic/types/mrr_response_data.rb +1 -1
  173. data/lib/schematic/types/onboarding_milestone_view.rb +1 -1
  174. data/lib/schematic/types/ordered_plans_in_group.rb +2 -0
  175. data/lib/schematic/types/plan_billing_source.rb +1 -0
  176. data/lib/schematic/types/plan_change_action.rb +1 -0
  177. data/lib/schematic/types/plan_change_amendment_status.rb +15 -0
  178. data/lib/schematic/types/plan_change_response_data.rb +4 -0
  179. data/lib/schematic/types/plan_credit_grant_view.rb +1 -1
  180. data/lib/schematic/types/plan_credit_order.rb +11 -0
  181. data/lib/schematic/types/plan_credit_visibility.rb +11 -0
  182. data/lib/schematic/types/plan_currency_price_request_body.rb +1 -1
  183. data/lib/schematic/types/plan_currency_prices_response_data.rb +1 -1
  184. data/lib/schematic/types/plan_entitlement_response_data.rb +3 -1
  185. data/lib/schematic/types/plan_group_plan_entitlements_order.rb +2 -0
  186. data/lib/schematic/types/plan_version_billing_product_change_response_data.rb +11 -0
  187. data/lib/schematic/types/plan_version_credit_grant_change_response_data.rb +17 -0
  188. data/lib/schematic/types/plan_version_diff_change_type.rb +13 -0
  189. data/lib/schematic/types/plan_version_diff_price_cadence.rb +14 -0
  190. data/lib/schematic/types/plan_version_diff_response_data.rb +23 -0
  191. data/lib/schematic/types/plan_version_entitlement_change_response_data.rb +17 -0
  192. data/lib/schematic/types/plan_version_field_change_response_data.rb +13 -0
  193. data/lib/schematic/types/plan_version_price_change_response_data.rb +15 -0
  194. data/lib/schematic/types/plan_view_public_response_data.rb +2 -0
  195. data/lib/schematic/types/preflight_request_body.rb +1 -1
  196. data/lib/schematic/types/preview_subscription_change_response_data.rb +3 -1
  197. data/lib/schematic/types/preview_subscription_discount_response_data.rb +2 -2
  198. data/lib/schematic/types/preview_subscription_finance_response_data.rb +2 -2
  199. data/lib/schematic/types/rulesengine_company.rb +1 -1
  200. data/lib/schematic/types/rulesengine_condition.rb +3 -1
  201. data/lib/schematic/types/rulesengine_credit_postpaid_config.rb +1 -1
  202. data/lib/schematic/types/rulesengine_credit_spend_policy.rb +2 -2
  203. data/lib/schematic/types/rulesengine_feature_entitlement.rb +8 -6
  204. data/lib/schematic/types/scheduled_downgrade_response_data.rb +1 -1
  205. data/lib/schematic/types/top_feature_by_usage_response_data.rb +1 -1
  206. data/lib/schematic/types/upcoming_invoice_response_data.rb +1 -1
  207. data/lib/schematic/types/update_billing_plan_credit_grant_request_body.rb +1 -1
  208. data/lib/schematic/types/update_entitlement_req_common.rb +3 -1
  209. data/lib/schematic/types/upsert_billing_product_request_body.rb +1 -1
  210. data/lib/schematic/types/usage_based_entitlement_request_body.rb +1 -1
  211. data/lib/schematic/types/usage_based_entitlement_response_data.rb +1 -1
  212. data/lib/schematic/types/user_credit_usage_response_data.rb +2 -2
  213. data/lib/schematic/types/user_daily_credit_point_response_data.rb +1 -1
  214. data/lib/schematic/types/user_feature_usage_response_data.rb +1 -1
  215. data/lib/schematic/version.rb +1 -1
  216. data/lib/schematic/wasm/rulesengine.wasm +0 -0
  217. data/lib/schematic/webhooks/client.rb +88 -10
  218. data/lib/schematic.rb +38 -3
  219. data/reference.md +340 -44
  220. metadata +37 -2
@@ -41,7 +41,14 @@ module Schematic
41
41
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::RunIntegrationResponse.load(response.body))
42
42
  else
43
43
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
44
- raise error_class.new(response.body, code: code)
44
+ error_types = {
45
+ 401 => Schematic::Types::ApiError,
46
+ 403 => Schematic::Types::ApiError,
47
+ 404 => Schematic::Types::ApiError,
48
+ 500 => Schematic::Types::ApiError
49
+ }
50
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
51
+ raise error_class.new(response.body, code: code, body: error_body)
45
52
  end
46
53
  end
47
54
 
@@ -100,7 +107,15 @@ module Schematic
100
107
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::ListIntegrationsResponse.load(response.body))
101
108
  else
102
109
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
103
- raise error_class.new(response.body, code: code)
110
+ error_types = {
111
+ 400 => Schematic::Types::ApiError,
112
+ 401 => Schematic::Types::ApiError,
113
+ 403 => Schematic::Types::ApiError,
114
+ 404 => Schematic::Types::ApiError,
115
+ 500 => Schematic::Types::ApiError
116
+ }
117
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
118
+ raise error_class.new(response.body, code: code, body: error_body)
104
119
  end
105
120
  end
106
121
 
@@ -135,7 +150,14 @@ module Schematic
135
150
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::GetIntegrationWebhookUrlResponse.load(response.body))
136
151
  else
137
152
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
138
- raise error_class.new(response.body, code: code)
153
+ error_types = {
154
+ 401 => Schematic::Types::ApiError,
155
+ 403 => Schematic::Types::ApiError,
156
+ 404 => Schematic::Types::ApiError,
157
+ 500 => Schematic::Types::ApiError
158
+ }
159
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
160
+ raise error_class.new(response.body, code: code, body: error_body)
139
161
  end
140
162
  end
141
163
 
@@ -170,7 +192,15 @@ module Schematic
170
192
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::InstallIntegrationResponse.load(response.body))
171
193
  else
172
194
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
173
- raise error_class.new(response.body, code: code)
195
+ error_types = {
196
+ 400 => Schematic::Types::ApiError,
197
+ 401 => Schematic::Types::ApiError,
198
+ 403 => Schematic::Types::ApiError,
199
+ 404 => Schematic::Types::ApiError,
200
+ 500 => Schematic::Types::ApiError
201
+ }
202
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
203
+ raise error_class.new(response.body, code: code, body: error_body)
174
204
  end
175
205
  end
176
206
 
@@ -205,7 +235,15 @@ module Schematic
205
235
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::StartDataImportResponse.load(response.body))
206
236
  else
207
237
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
208
- raise error_class.new(response.body, code: code)
238
+ error_types = {
239
+ 400 => Schematic::Types::ApiError,
240
+ 401 => Schematic::Types::ApiError,
241
+ 403 => Schematic::Types::ApiError,
242
+ 404 => Schematic::Types::ApiError,
243
+ 500 => Schematic::Types::ApiError
244
+ }
245
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
246
+ raise error_class.new(response.body, code: code, body: error_body)
209
247
  end
210
248
  end
211
249
 
@@ -238,7 +276,14 @@ module Schematic
238
276
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::LoadSampleDataSetResponse.load(response.body))
239
277
  else
240
278
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
241
- raise error_class.new(response.body, code: code)
279
+ error_types = {
280
+ 401 => Schematic::Types::ApiError,
281
+ 403 => Schematic::Types::ApiError,
282
+ 404 => Schematic::Types::ApiError,
283
+ 500 => Schematic::Types::ApiError
284
+ }
285
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
286
+ raise error_class.new(response.body, code: code, body: error_body)
242
287
  end
243
288
  end
244
289
 
@@ -271,7 +316,14 @@ module Schematic
271
316
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::GetStripeSandboxClaimLinkResponse.load(response.body))
272
317
  else
273
318
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
274
- raise error_class.new(response.body, code: code)
319
+ error_types = {
320
+ 401 => Schematic::Types::ApiError,
321
+ 403 => Schematic::Types::ApiError,
322
+ 404 => Schematic::Types::ApiError,
323
+ 500 => Schematic::Types::ApiError
324
+ }
325
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
326
+ raise error_class.new(response.body, code: code, body: error_body)
275
327
  end
276
328
  end
277
329
 
@@ -304,7 +356,14 @@ module Schematic
304
356
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::GetStripeSandboxKeysResponse.load(response.body))
305
357
  else
306
358
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
307
- raise error_class.new(response.body, code: code)
359
+ error_types = {
360
+ 401 => Schematic::Types::ApiError,
361
+ 403 => Schematic::Types::ApiError,
362
+ 404 => Schematic::Types::ApiError,
363
+ 500 => Schematic::Types::ApiError
364
+ }
365
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
366
+ raise error_class.new(response.body, code: code, body: error_body)
308
367
  end
309
368
  end
310
369
 
@@ -339,7 +398,15 @@ module Schematic
339
398
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::ClaimStripeSandboxKeysResponse.load(response.body))
340
399
  else
341
400
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
342
- raise error_class.new(response.body, code: code)
401
+ error_types = {
402
+ 400 => Schematic::Types::ApiError,
403
+ 401 => Schematic::Types::ApiError,
404
+ 403 => Schematic::Types::ApiError,
405
+ 404 => Schematic::Types::ApiError,
406
+ 500 => Schematic::Types::ApiError
407
+ }
408
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
409
+ raise error_class.new(response.body, code: code, body: error_body)
343
410
  end
344
411
  end
345
412
 
@@ -374,7 +441,15 @@ module Schematic
374
441
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::AssumeStripeInstalledResponse.load(response.body))
375
442
  else
376
443
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
377
- raise error_class.new(response.body, code: code)
444
+ error_types = {
445
+ 400 => Schematic::Types::ApiError,
446
+ 401 => Schematic::Types::ApiError,
447
+ 403 => Schematic::Types::ApiError,
448
+ 404 => Schematic::Types::ApiError,
449
+ 500 => Schematic::Types::ApiError
450
+ }
451
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
452
+ raise error_class.new(response.body, code: code, body: error_body)
378
453
  end
379
454
  end
380
455
 
@@ -409,7 +484,15 @@ module Schematic
409
484
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::InstallStripeResponse.load(response.body))
410
485
  else
411
486
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
412
- raise error_class.new(response.body, code: code)
487
+ error_types = {
488
+ 400 => Schematic::Types::ApiError,
489
+ 401 => Schematic::Types::ApiError,
490
+ 403 => Schematic::Types::ApiError,
491
+ 404 => Schematic::Types::ApiError,
492
+ 500 => Schematic::Types::ApiError
493
+ }
494
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
495
+ raise error_class.new(response.body, code: code, body: error_body)
413
496
  end
414
497
  end
415
498
 
@@ -444,7 +527,15 @@ module Schematic
444
527
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::InstallStripeClaimableSandboxResponse.load(response.body))
445
528
  else
446
529
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
447
- raise error_class.new(response.body, code: code)
530
+ error_types = {
531
+ 400 => Schematic::Types::ApiError,
532
+ 401 => Schematic::Types::ApiError,
533
+ 403 => Schematic::Types::ApiError,
534
+ 404 => Schematic::Types::ApiError,
535
+ 500 => Schematic::Types::ApiError
536
+ }
537
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
538
+ raise error_class.new(response.body, code: code, body: error_body)
448
539
  end
449
540
  end
450
541
 
@@ -477,7 +568,14 @@ module Schematic
477
568
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::ListStripeSandboxCountriesResponse.load(response.body))
478
569
  else
479
570
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
480
- raise error_class.new(response.body, code: code)
571
+ error_types = {
572
+ 401 => Schematic::Types::ApiError,
573
+ 403 => Schematic::Types::ApiError,
574
+ 404 => Schematic::Types::ApiError,
575
+ 500 => Schematic::Types::ApiError
576
+ }
577
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
578
+ raise error_class.new(response.body, code: code, body: error_body)
481
579
  end
482
580
  end
483
581
 
@@ -512,7 +610,15 @@ module Schematic
512
610
  (response.body.to_s.empty? ? nil : Schematic::Integrationsapi::Types::UninstallIntegrationResponse.load(response.body))
513
611
  else
514
612
  error_class = Schematic::Errors::ResponseError.subclass_for_code(code)
515
- raise error_class.new(response.body, code: code)
613
+ error_types = {
614
+ 400 => Schematic::Types::ApiError,
615
+ 401 => Schematic::Types::ApiError,
616
+ 403 => Schematic::Types::ApiError,
617
+ 404 => Schematic::Types::ApiError,
618
+ 500 => Schematic::Types::ApiError
619
+ }
620
+ error_body = Schematic::Errors::ResponseError.load_error_body(code, response.body, error_types)
621
+ raise error_class.new(response.body, code: code, body: error_body)
516
622
  end
517
623
  end
518
624
  end
@@ -28,12 +28,42 @@ module Schematic
28
28
  @query.merge(additional_query)
29
29
  end
30
30
 
31
+ # @return [Hash] The additional body parameters from request options, keyed by wire-format name.
32
+ def additional_body_parameters
33
+ @request_options&.dig(:additional_body_parameters) || @request_options&.dig("additional_body_parameters") || {}
34
+ end
35
+
31
36
  # Child classes should implement:
32
37
  # - encode_headers: Returns the encoded HTTP request headers.
33
38
  # - encode_body: Returns the encoded HTTP request body.
34
39
 
35
40
  private
36
41
 
42
+ # Merges additional_body_parameters from request_options on top of the request body.
43
+ # Keys are used as-is (API wire-format names) and are normalized to strings so that a
44
+ # caller-supplied key always overrides the SDK-serialized field with the same name.
45
+ # When the body is nil the additional parameters become the body, except for GET and HEAD
46
+ # requests, which are sent without a body (the additional parameters are ignored). Bodies
47
+ # that are not hash-like (arrays, primitives) are returned unchanged.
48
+ # @param body [Object, nil] The request body.
49
+ # @return [Object, nil] The merged request body.
50
+ def merge_additional_body_parameters(body)
51
+ additional_body = additional_body_parameters
52
+ return body if additional_body.nil? || additional_body.empty?
53
+ return body if body.nil? && bodyless_method?
54
+
55
+ additional_body = additional_body.to_h.transform_keys(&:to_s)
56
+ return additional_body if body.nil?
57
+ return body if body.is_a?(::Array) || !body.respond_to?(:to_h)
58
+
59
+ body.to_h.transform_keys(&:to_s).merge(additional_body)
60
+ end
61
+
62
+ # @return [Boolean] Whether the request method is one that is sent without a body (GET, HEAD).
63
+ def bodyless_method?
64
+ %w[GET HEAD].include?(@method.to_s.upcase)
65
+ end
66
+
37
67
  # Merges additional_headers from request_options into sdk_headers, filtering out
38
68
  # any keys that collide with SDK-set or client-protected headers (case-insensitive).
39
69
  # @param sdk_headers [Hash] Headers set by the SDK for this request type.
@@ -47,6 +47,7 @@ module Schematic
47
47
  # Resolve auth headers once per request (not per retry) so token-based
48
48
  # providers refresh at most once here; static providers are cheap.
49
49
  auth_headers = resolve_auth_headers
50
+ timeout = request_timeout(request)
50
51
  attempt = 0
51
52
  response = nil
52
53
 
@@ -60,12 +61,12 @@ module Schematic
60
61
  )
61
62
 
62
63
  conn = connect(url)
63
- conn.open_timeout = @timeout
64
- conn.read_timeout = @timeout
65
- conn.write_timeout = @timeout
66
- conn.continue_timeout = @timeout
64
+ conn.open_timeout = timeout
65
+ conn.read_timeout = timeout
66
+ conn.write_timeout = timeout
67
+ conn.continue_timeout = timeout
67
68
 
68
- response = conn.request(http_request)
69
+ response = wrap_transport_errors { conn.request(http_request) }
69
70
 
70
71
  break unless should_retry?(response, attempt)
71
72
 
@@ -77,6 +78,35 @@ module Schematic
77
78
  response
78
79
  end
79
80
 
81
+ # Socket-level `Errno` failures. Other `SystemCallError`s, such as file errors raised by a
82
+ # custom HTTP client, are not connection failures and propagate unchanged.
83
+ NETWORK_ERRNOS = [
84
+ Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ECONNABORTED, Errno::EPIPE,
85
+ Errno::EHOSTUNREACH, Errno::ENETUNREACH, Errno::ENETDOWN, Errno::EHOSTDOWN,
86
+ Errno::EADDRNOTAVAIL
87
+ ].freeze
88
+
89
+ # Runs a single request attempt, re-raising transport failures as SDK errors so that
90
+ # rescuing `Errors::ApiError` covers them. The original exception is kept as `cause`.
91
+ # These failures are not retried: the server may already have processed the request.
92
+ # @return [Net::HTTPResponse] The HTTP response.
93
+ def wrap_transport_errors
94
+ yield
95
+ rescue Net::OpenTimeout, Net::ReadTimeout, Net::WriteTimeout, Errno::ETIMEDOUT => e
96
+ raise Schematic::Errors::TimeoutError, e.message
97
+ rescue EOFError, SocketError, OpenSSL::SSL::SSLError, *NETWORK_ERRNOS,
98
+ Net::ProtocolError, Net::HTTPBadResponse, Net::HTTPHeaderSyntaxError => e
99
+ raise Schematic::Errors::ConnectionError, e.message
100
+ end
101
+
102
+ # @param request [Schematic::Internal::Http::BaseRequest] The HTTP request.
103
+ # @return [Float] The request's `timeout_in_seconds` option, or the client-level timeout.
104
+ def request_timeout(request)
105
+ options = request.request_options || {}
106
+ timeout = options.key?(:timeout_in_seconds) ? options[:timeout_in_seconds] : options["timeout_in_seconds"]
107
+ (timeout.nil? ? @timeout : timeout).to_f
108
+ end
109
+
80
110
  # The client-level header names that `additional_headers` must not replace: every default
81
111
  # header except the API's global headers, which are overridable per request.
82
112
  # @return [Array<Symbol, String>] The protected header names.
@@ -10,11 +10,16 @@ module Schematic
10
10
  # @param item_field [Symbol] The field in API responses to extract the items to iterate over.
11
11
  # @param block [Proc] A block which is responsible for receiving a cursor to use and returning the given page from the API.
12
12
  # @return [Schematic::Internal::CursorItemIterator]
13
- def initialize(initial_cursor:, cursor_field:, item_field:, &)
13
+ def initialize(initial_cursor:, cursor_field:, item_field:, &block)
14
14
  super()
15
15
  @item_field = item_field
16
- @page_iterator = CursorPageIterator.new(initial_cursor:, cursor_field:, &)
16
+ @http_response = nil
17
+ get_page = track_http_responses(block)
18
+ @page_iterator = CursorPageIterator.new(initial_cursor:, cursor_field:, &get_page)
19
+ # Items are read through their own page cursor so that reading `pages` never skips items.
20
+ @item_pages = CursorPageIterator.new(initial_cursor:, cursor_field:, &get_page)
17
21
  @page = nil
22
+ @item_index = 0
18
23
  end
19
24
 
20
25
  # Returns the CursorPageIterator mediating access to the underlying API.
@@ -17,45 +17,99 @@ module Schematic
17
17
  # The block should return a two-element array: [parsed_page, raw_http_response].
18
18
  # @return [Schematic::Internal::CursorPageIterator]
19
19
  def initialize(initial_cursor:, cursor_field:, &block)
20
- @need_initial_load = initial_cursor.nil?
21
- @cursor = initial_cursor
20
+ @initial_cursor = initial_cursor
22
21
  @cursor_field = cursor_field
23
22
  @get_next_page = block
24
23
  @http_response = nil
24
+ @first_page_requested = false
25
+ @first_page = nil
26
+ rewind
25
27
  end
26
28
 
27
- # Iterates over each page returned by the API.
29
+ # Sends the request for the first page now instead of on the first iteration, so an API error for that page
30
+ # is raised here. The page is kept, and every loop that starts from the first page reuses it instead of
31
+ # requesting it again. Does nothing if the first page was already requested.
28
32
  #
29
- # @param block [Proc] The block which each retrieved page is yielded to.
33
+ # @return [self]
34
+ def load_first_page
35
+ return self if @first_page_requested
36
+
37
+ @first_page = fetch_page(@initial_cursor)
38
+ rewind
39
+ self
40
+ end
41
+
42
+ # Uses the first page that `other` loaded with `load_first_page`, unless this iterator already sent a request.
43
+ #
44
+ # @param other [Schematic::Internal::CursorPageIterator]
30
45
  # @return [NilClass]
46
+ def reuse_first_page(other)
47
+ return if @first_page_requested || other.first_page.nil?
48
+
49
+ @first_page = other.first_page
50
+ rewind
51
+ end
52
+
53
+ # Iterates over each page returned by the API, starting again from the first page on every call.
54
+ #
55
+ # @param block [Proc] The block which each retrieved page is yielded to.
56
+ # @return [NilClass, Enumerator] An Enumerator when no block is given.
31
57
  def each(&block)
58
+ return enum_for(:each) unless block_given?
59
+
60
+ rewind
32
61
  while (page = next_page)
33
62
  block.call(page)
34
63
  end
35
64
  end
36
65
 
66
+ # Resets page-by-page iteration (`next_page` / `next?`) to the first page.
67
+ #
68
+ # @return [NilClass]
69
+ def rewind
70
+ @need_initial_load = @initial_cursor.nil?
71
+ @cursor = @initial_cursor
72
+ @at_first_page = true
73
+ nil
74
+ end
75
+
37
76
  # Whether another page will be available from the API.
38
77
  #
39
78
  # @return [Boolean]
40
79
  def next?
41
- @need_initial_load || !@cursor.nil?
80
+ (@at_first_page && !@first_page.nil?) || @need_initial_load || !@cursor.nil?
42
81
  end
43
82
 
44
83
  # Retrieves the next page from the API.
45
84
  #
46
85
  # @return [Object, nil]
47
86
  def next_page
48
- return if !@need_initial_load && @cursor.nil?
49
-
50
- @need_initial_load = false
51
- result = @get_next_page.call(@cursor)
52
- if result.is_a?(Array)
53
- fetched_page, raw_response = result
54
- @http_response = raw_response
87
+ if @at_first_page && !@first_page.nil?
88
+ page = @first_page
55
89
  else
56
- fetched_page = result
90
+ return if !@need_initial_load && @cursor.nil?
91
+
92
+ page = fetch_page(@cursor)
57
93
  end
58
- @cursor = fetched_page.send(@cursor_field)
94
+ @at_first_page = false
95
+ @need_initial_load = false
96
+ @cursor = page.send(@cursor_field)
97
+ page
98
+ end
99
+
100
+ protected
101
+
102
+ attr_reader :first_page
103
+
104
+ private
105
+
106
+ def fetch_page(cursor)
107
+ result = @get_next_page.call(cursor)
108
+ @first_page_requested = true
109
+ return result unless result.is_a?(Array)
110
+
111
+ fetched_page, raw_response = result
112
+ @http_response = raw_response
59
113
  fetched_page
60
114
  end
61
115
  end
@@ -5,20 +5,35 @@ module Schematic
5
5
  class ItemIterator
6
6
  include Enumerable
7
7
 
8
- # The raw HTTP response from the most recent page response.
8
+ # The raw HTTP response from the most recent page request made by this pager or its `pages`.
9
9
  # @return [Net::HTTPResponse, nil]
10
- def http_response
11
- @page_iterator&.http_response
12
- end
10
+ attr_reader :http_response
13
11
 
14
- # Iterates over each item returned by the API.
12
+ # Iterates over each item returned by the API, starting again from the first page on every call.
13
+ # Each loop is independent of other loops and of `next_element`.
15
14
  #
16
15
  # @param block [Proc] The block which each retrieved item is yielded to.
17
- # @return [NilClass]
18
- def each(&block)
19
- while (item = next_element)
20
- block.call(item)
16
+ # @return [NilClass, Enumerator] An Enumerator when no block is given.
17
+ def each(&)
18
+ return enum_for(:each) unless block_given?
19
+
20
+ # Each loop reads through its own copy of the page stream, so repeated or nested loops never
21
+ # share a position with each other or with `next_element`.
22
+ pass = @item_pages.dup.tap(&:rewind)
23
+ while (page = pass.next_page)
24
+ (page.send(@item_field) || []).each(&)
21
25
  end
26
+ nil
27
+ end
28
+
29
+ # Resets manual item-by-item iteration (`next_element` / `next?`) to the first page.
30
+ #
31
+ # @return [NilClass]
32
+ def rewind
33
+ @item_pages.rewind
34
+ @page = nil
35
+ @item_index = 0
36
+ nil
22
37
  end
23
38
 
24
39
  # Whether another item will be available from the API.
@@ -34,6 +49,19 @@ module Schematic
34
49
  any_items_in_cached_page?
35
50
  end
36
51
 
52
+ # Sends the request for the first page now instead of on the first iteration, so an API error for that page
53
+ # is raised here. The page is kept, and every loop (over items or `pages`) that starts from the first page
54
+ # reuses it instead of requesting it again. Does nothing if this pager already sent a request.
55
+ #
56
+ # @return [self]
57
+ def load_first_page
58
+ return self if @requested
59
+
60
+ @item_pages.load_first_page
61
+ @page_iterator.reuse_first_page(@item_pages)
62
+ self
63
+ end
64
+
37
65
  # Retrieves the next item from the API.
38
66
  def next_element
39
67
  item = next_item_from_cached_page
@@ -45,20 +73,38 @@ module Schematic
45
73
 
46
74
  private
47
75
 
76
+ # Wraps the page-fetching block so that `http_response` reflects the most recent request.
77
+ def track_http_responses(get_page)
78
+ proc do |*args|
79
+ result = get_page.call(*args)
80
+ @requested = true
81
+ @http_response = result[1] if result.is_a?(Array)
82
+ result
83
+ end
84
+ end
85
+
86
+ def cached_page_items
87
+ return [] unless @page
88
+
89
+ @page.send(@item_field) || []
90
+ end
91
+
48
92
  def next_item_from_cached_page
49
- return unless @page
93
+ items = cached_page_items
94
+ return if @item_index >= items.length
50
95
 
51
- @page.send(@item_field).shift
96
+ item = items[@item_index]
97
+ @item_index += 1
98
+ item
52
99
  end
53
100
 
54
101
  def any_items_in_cached_page?
55
- return false unless @page
56
-
57
- !@page.send(@item_field).empty?
102
+ @item_index < cached_page_items.length
58
103
  end
59
104
 
60
105
  def load_next_page
61
- @page = @page_iterator.next_page
106
+ @page = @item_pages.next_page
107
+ @item_index = 0
62
108
  end
63
109
  end
64
110
  end
@@ -12,11 +12,16 @@ module Schematic
12
12
  # @param block [Proc] A block which is responsible for receiving a page number to use and returning the given page from the API.
13
13
  #
14
14
  # @return [Schematic::Internal::OffsetItemIterator]
15
- def initialize(initial_page:, item_field:, has_next_field:, step:, &)
15
+ def initialize(initial_page:, item_field:, has_next_field:, step:, &block)
16
16
  super()
17
17
  @item_field = item_field
18
- @page_iterator = OffsetPageIterator.new(initial_page:, item_field:, has_next_field:, step:, &)
18
+ @http_response = nil
19
+ get_page = track_http_responses(block)
20
+ @page_iterator = OffsetPageIterator.new(initial_page:, item_field:, has_next_field:, step:, &get_page)
21
+ # Items are read through their own page cursor so that reading `pages` never skips items.
22
+ @item_pages = OffsetPageIterator.new(initial_page:, item_field:, has_next_field:, step:, &get_page)
19
23
  @page = nil
24
+ @item_index = 0
20
25
  end
21
26
 
22
27
  # Returns the OffsetPageIterator that is mediating access to the underlying API.