test-test-sink-test-test 0.0.2.pre.alpha.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (265) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +151 -0
  3. data/lib/sink/base_client.rb +404 -0
  4. data/lib/sink/base_model.rb +226 -0
  5. data/lib/sink/client.rb +391 -0
  6. data/lib/sink/fake_page.rb +44 -0
  7. data/lib/sink/models/address.rb +55 -0
  8. data/lib/sink/models/allof_base_parent.rb +18 -0
  9. data/lib/sink/models/allof_multiple_inline_entries.rb +15 -0
  10. data/lib/sink/models/api_status.rb +18 -0
  11. data/lib/sink/models/array_float_items_response.rb +6 -0
  12. data/lib/sink/models/array_missing_items_response.rb +18 -0
  13. data/lib/sink/models/array_object_items.rb +18 -0
  14. data/lib/sink/models/array_object_items_response.rb +18 -0
  15. data/lib/sink/models/array_recursion.rb +6 -0
  16. data/lib/sink/models/balance.rb +18 -0
  17. data/lib/sink/models/basic_shared_model_object.rb +23 -0
  18. data/lib/sink/models/body_param_top_level_all_of_response.rb +28 -0
  19. data/lib/sink/models/body_param_top_level_any_of_response.rb +6 -0
  20. data/lib/sink/models/body_param_top_level_one_of_response.rb +6 -0
  21. data/lib/sink/models/body_param_union_overlapping_prop_response.rb +19 -0
  22. data/lib/sink/models/card.rb +211 -0
  23. data/lib/sink/models/card_list_response.rb +36 -0
  24. data/lib/sink/models/card_provision_foo_response.rb +18 -0
  25. data/lib/sink/models/child_inlined_response_response.rb +18 -0
  26. data/lib/sink/models/child_model.rb +36 -0
  27. data/lib/sink/models/class_.rb +18 -0
  28. data/lib/sink/models/client.rb +23 -0
  29. data/lib/sink/models/company.rb +18 -0
  30. data/lib/sink/models/company_payment.rb +18 -0
  31. data/lib/sink/models/complex_query_array_query_response.rb +26 -0
  32. data/lib/sink/models/config_tool_model_ref_from_nested_response_body_response.rb +32 -0
  33. data/lib/sink/models/currency.rb +23 -0
  34. data/lib/sink/models/decorator_test_keep_me_response.rb +18 -0
  35. data/lib/sink/models/docstring_leading_double_quote_response.rb +20 -0
  36. data/lib/sink/models/docstring_trailing_double_quote_response.rb +32 -0
  37. data/lib/sink/models/documents.rb +23 -0
  38. data/lib/sink/models/eeoc.rb +18 -0
  39. data/lib/sink/models/employment_data.rb +18 -0
  40. data/lib/sink/models/enum_basic_response.rb +62 -0
  41. data/lib/sink/models/envelope_inline_response_response.rb +18 -0
  42. data/lib/sink/models/envelope_wrapped_array_response.rb +6 -0
  43. data/lib/sink/models/export.rb +19 -0
  44. data/lib/sink/models/file_create_multipart_response.rb +18 -0
  45. data/lib/sink/models/file_everything_multipart_response.rb +19 -0
  46. data/lib/sink/models/file_no_file_multipart_response.rb +18 -0
  47. data/lib/sink/models/file_with_optional_param_response.rb +18 -0
  48. data/lib/sink/models/funding_account.rb +100 -0
  49. data/lib/sink/models/import.rb +18 -0
  50. data/lib/sink/models/interface.rb +18 -0
  51. data/lib/sink/models/keep_this_resource_keep_this_method_response.rb +19 -0
  52. data/lib/sink/models/make_ambiguous_schemas_explicit_make_ambiguous_schemas_explicit_response.rb +45 -0
  53. data/lib/sink/models/make_ambiguous_schemas_looser_make_ambiguous_schemas_looser_response.rb +45 -0
  54. data/lib/sink/models/map_nullable_items_response.rb +28 -0
  55. data/lib/sink/models/method_config_skipped_tests_all_response.rb +19 -0
  56. data/lib/sink/models/method_config_skipped_tests_go_response.rb +19 -0
  57. data/lib/sink/models/method_config_skipped_tests_java_response.rb +19 -0
  58. data/lib/sink/models/method_config_skipped_tests_kotlin_response.rb +19 -0
  59. data/lib/sink/models/method_config_skipped_tests_node_and_python_response.rb +19 -0
  60. data/lib/sink/models/method_config_skipped_tests_node_response.rb +19 -0
  61. data/lib/sink/models/method_config_skipped_tests_python_response.rb +19 -0
  62. data/lib/sink/models/method_config_skipped_tests_ruby_response.rb +19 -0
  63. data/lib/sink/models/model_from_nested_path.rb +39 -0
  64. data/lib/sink/models/model_from_nested_response_body_ref.rb +18 -0
  65. data/lib/sink/models/model_from_schemas_ref.rb +18 -0
  66. data/lib/sink/models/model_from_schemas_ref_openapi_uri.rb +18 -0
  67. data/lib/sink/models/model_from_schemas_ref_openapi_uri_jmespath.rb +19 -0
  68. data/lib/sink/models/model_from_schemas_ref_openapi_uri_jsonpath.rb +19 -0
  69. data/lib/sink/models/model_level_1.rb +22 -0
  70. data/lib/sink/models/model_level_2.rb +22 -0
  71. data/lib/sink/models/model_level_3.rb +22 -0
  72. data/lib/sink/models/model_referenced_in_parent_and_child.rb +19 -0
  73. data/lib/sink/models/model_with_nested_model.rb +24 -0
  74. data/lib/sink/models/my_model.rb +18 -0
  75. data/lib/sink/models/name_child_prop_import_clash_response.rb +37 -0
  76. data/lib/sink/models/name_properties_common_conflicts_response.rb +84 -0
  77. data/lib/sink/models/name_properties_illegal_go_identifiers_response.rb +19 -0
  78. data/lib/sink/models/name_properties_illegal_javascript_identifiers_response.rb +6 -0
  79. data/lib/sink/models/name_response_property_clashes_model_import_response.rb +24 -0
  80. data/lib/sink/models/name_response_shadows_pydantic_response.rb +24 -0
  81. data/lib/sink/models/nested_request_model_a.rb +18 -0
  82. data/lib/sink/models/nested_request_model_b.rb +18 -0
  83. data/lib/sink/models/nested_request_model_c.rb +31 -0
  84. data/lib/sink/models/object_missing_items_response.rb +18 -0
  85. data/lib/sink/models/object_mixed_known_and_unknown_response.rb +19 -0
  86. data/lib/sink/models/object_multiple_array_properties_same_ref_response.rb +73 -0
  87. data/lib/sink/models/object_multiple_properties_same_model_response.rb +29 -0
  88. data/lib/sink/models/object_multiple_properties_same_ref_response.rb +68 -0
  89. data/lib/sink/models/object_skipped_props.rb +38 -0
  90. data/lib/sink/models/object_two_dimensional_array_primitive_property_response.rb +34 -0
  91. data/lib/sink/models/object_with_any_of_null_property.rb +31 -0
  92. data/lib/sink/models/object_with_child_ref.rb +23 -0
  93. data/lib/sink/models/object_with_one_of_null_property.rb +31 -0
  94. data/lib/sink/models/object_with_union_properties.rb +23 -0
  95. data/lib/sink/models/openapi_format_array_type_one_entry_response.rb +19 -0
  96. data/lib/sink/models/openapi_format_array_type_one_entry_with_null_response.rb +19 -0
  97. data/lib/sink/models/openapi_special_used_used_as_property_name_response.rb +19 -0
  98. data/lib/sink/models/page_cursor_shared_ref_pagination.rb +23 -0
  99. data/lib/sink/models/parent_model_with_child_ref.rb +28 -0
  100. data/lib/sink/models/path_param_colon_suffix_response.rb +18 -0
  101. data/lib/sink/models/path_param_file_extension_response.rb +18 -0
  102. data/lib/sink/models/path_param_multiple_response.rb +18 -0
  103. data/lib/sink/models/path_param_query_param_response.rb +18 -0
  104. data/lib/sink/models/path_param_singular_response.rb +18 -0
  105. data/lib/sink/models/primitive_strings_response.rb +18 -0
  106. data/lib/sink/models/private.rb +18 -0
  107. data/lib/sink/models/public.rb +18 -0
  108. data/lib/sink/models/recursion_create_envelope_response.rb +19 -0
  109. data/lib/sink/models/response_allof_simple_response.rb +23 -0
  110. data/lib/sink/models/response_array_object_with_union_properties_response.rb +6 -0
  111. data/lib/sink/models/response_array_response_response.rb +6 -0
  112. data/lib/sink/models/response_missing_required_response.rb +24 -0
  113. data/lib/sink/models/response_nested_array_response.rb +36 -0
  114. data/lib/sink/models/response_object_all_properties_response.rb +65 -0
  115. data/lib/sink/models/response_object_no_properties_response.rb +14 -0
  116. data/lib/sink/models/response_object_with_additional_properties_prop_response.rb +32 -0
  117. data/lib/sink/models/response_object_with_heavily_nested_union_response.rb +19 -0
  118. data/lib/sink/models/response_only_read_only_properties_response.rb +25 -0
  119. data/lib/sink/models/responses_allof_cross_object.rb +23 -0
  120. data/lib/sink/models/return_.rb +18 -0
  121. data/lib/sink/models/root_response.rb +31 -0
  122. data/lib/sink/models/self_recursion.rb +23 -0
  123. data/lib/sink/models/shared_cursor_nested_response_prop_meta.rb +33 -0
  124. data/lib/sink/models/shared_self_recursion.rb +23 -0
  125. data/lib/sink/models/shipping_address.rb +85 -0
  126. data/lib/sink/models/simple_allof.rb +28 -0
  127. data/lib/sink/models/simple_object.rb +32 -0
  128. data/lib/sink/models/skip_this_resource_i_never_appear_response.rb +19 -0
  129. data/lib/sink/models/streaming_basic_response.rb +23 -0
  130. data/lib/sink/models/streaming_nested_params_response.rb +23 -0
  131. data/lib/sink/models/streaming_no_discriminator_response.rb +24 -0
  132. data/lib/sink/models/streaming_query_param_discriminator_response.rb +24 -0
  133. data/lib/sink/models/streaming_with_unrelated_default_param_response.rb +24 -0
  134. data/lib/sink/models/type_dates_response.rb +38 -0
  135. data/lib/sink/models/type_datetimes_response.rb +38 -0
  136. data/lib/sink/models/union_discriminated_variant_a.rb +27 -0
  137. data/lib/sink/models/union_discriminated_variant_b.rb +27 -0
  138. data/lib/sink/models/union_response_discriminated_by_property_name_response.rb +6 -0
  139. data/lib/sink/models/union_response_discriminated_with_basic_mapping_response.rb +6 -0
  140. data/lib/sink/models/union_type_mixed_types_response.rb +6 -0
  141. data/lib/sink/models/union_type_nullable_union_response.rb +6 -0
  142. data/lib/sink/models/union_type_objects_response.rb +6 -0
  143. data/lib/sink/models/union_type_super_mixed_types_response.rb +6 -0
  144. data/lib/sink/models/union_type_unknown_variant_response.rb +6 -0
  145. data/lib/sink/models/version_1_30_name_create_response.rb +18 -0
  146. data/lib/sink/models/widget.rb +19 -0
  147. data/lib/sink/models/write_only_response_simple_response.rb +21 -0
  148. data/lib/sink/page_cursor.rb +54 -0
  149. data/lib/sink/page_cursor_from_headers.rb +54 -0
  150. data/lib/sink/page_cursor_id.rb +50 -0
  151. data/lib/sink/page_cursor_nested_items.rb +84 -0
  152. data/lib/sink/page_cursor_nested_object_ref.rb +71 -0
  153. data/lib/sink/page_cursor_shared_ref.rb +72 -0
  154. data/lib/sink/page_cursor_top_level_array.rb +51 -0
  155. data/lib/sink/page_cursor_url.rb +51 -0
  156. data/lib/sink/page_cursor_with_reverse.rb +58 -0
  157. data/lib/sink/page_offset.rb +54 -0
  158. data/lib/sink/page_offset_no_start_field.rb +50 -0
  159. data/lib/sink/page_offset_total_count.rb +58 -0
  160. data/lib/sink/page_page_number.rb +58 -0
  161. data/lib/sink/page_page_number_without_current_page_response.rb +50 -0
  162. data/lib/sink/pooled_net_requester.rb +72 -0
  163. data/lib/sink/request_options.rb +89 -0
  164. data/lib/sink/resources/body_params/objects.rb +34 -0
  165. data/lib/sink/resources/body_params/unions.rb +34 -0
  166. data/lib/sink/resources/body_params.rb +630 -0
  167. data/lib/sink/resources/cards.rb +508 -0
  168. data/lib/sink/resources/casing/eeoc.rb +34 -0
  169. data/lib/sink/resources/casing.rb +16 -0
  170. data/lib/sink/resources/clients.rb +30 -0
  171. data/lib/sink/resources/company/payments.rb +30 -0
  172. data/lib/sink/resources/company.rb +18 -0
  173. data/lib/sink/resources/complex_queries.rb +60 -0
  174. data/lib/sink/resources/config_tools/parent_with_skip_node_python/child_only_skip_python.rb +99 -0
  175. data/lib/sink/resources/config_tools/parent_with_skip_node_python.rb +101 -0
  176. data/lib/sink/resources/config_tools.rb +40 -0
  177. data/lib/sink/resources/decorator_tests/keep_this_resource.rb +29 -0
  178. data/lib/sink/resources/decorator_tests/languages.rb +59 -0
  179. data/lib/sink/resources/decorator_tests/skip_this_resource.rb +28 -0
  180. data/lib/sink/resources/decorator_tests.rb +38 -0
  181. data/lib/sink/resources/deeply_nested/level_one/level_two/level_three.rb +33 -0
  182. data/lib/sink/resources/deeply_nested/level_one/level_two.rb +35 -0
  183. data/lib/sink/resources/deeply_nested/level_one.rb +33 -0
  184. data/lib/sink/resources/deeply_nested.rb +16 -0
  185. data/lib/sink/resources/docstrings.rb +82 -0
  186. data/lib/sink/resources/empty_body.rb +60 -0
  187. data/lib/sink/resources/envelopes.rb +74 -0
  188. data/lib/sink/resources/files.rb +101 -0
  189. data/lib/sink/resources/header_params.rb +81 -0
  190. data/lib/sink/resources/invalid_schemas/arrays.rb +26 -0
  191. data/lib/sink/resources/invalid_schemas/objects.rb +26 -0
  192. data/lib/sink/resources/invalid_schemas.rb +20 -0
  193. data/lib/sink/resources/make_ambiguous_schemas_explicit.rb +26 -0
  194. data/lib/sink/resources/make_ambiguous_schemas_looser.rb +26 -0
  195. data/lib/sink/resources/method_config.rb +167 -0
  196. data/lib/sink/resources/mixed_params/duplicates.rb +79 -0
  197. data/lib/sink/resources/mixed_params.rb +88 -0
  198. data/lib/sink/resources/model_referenced_in_parent_and_child/child.rb +26 -0
  199. data/lib/sink/resources/model_referenced_in_parent_and_child.rb +28 -0
  200. data/lib/sink/resources/names/can_cause_clashes/employment_data.rb +16 -0
  201. data/lib/sink/resources/names/can_cause_clashes/response.rb +32 -0
  202. data/lib/sink/resources/names/can_cause_clashes.rb +23 -0
  203. data/lib/sink/resources/names/documents.rb +28 -0
  204. data/lib/sink/resources/names/openapi_specials.rb +26 -0
  205. data/lib/sink/resources/names/params.rb +52 -0
  206. data/lib/sink/resources/names/reserved_names/import.rb +31 -0
  207. data/lib/sink/resources/names/reserved_names/methods.rb +40 -0
  208. data/lib/sink/resources/names/reserved_names/public/class_.rb +30 -0
  209. data/lib/sink/resources/names/reserved_names/public/interface.rb +30 -0
  210. data/lib/sink/resources/names/reserved_names/public/private.rb +30 -0
  211. data/lib/sink/resources/names/reserved_names/public.rb +40 -0
  212. data/lib/sink/resources/names/reserved_names.rb +46 -0
  213. data/lib/sink/resources/names.rb +170 -0
  214. data/lib/sink/resources/openapi_formats.rb +53 -0
  215. data/lib/sink/resources/pagination_tests/cursor.rb +57 -0
  216. data/lib/sink/resources/pagination_tests/cursor_id.rb +34 -0
  217. data/lib/sink/resources/pagination_tests/cursor_url.rb +34 -0
  218. data/lib/sink/resources/pagination_tests/fake_pages.rb +33 -0
  219. data/lib/sink/resources/pagination_tests/items_types.rb +34 -0
  220. data/lib/sink/resources/pagination_tests/nested_items.rb +34 -0
  221. data/lib/sink/resources/pagination_tests/offset.rb +74 -0
  222. data/lib/sink/resources/pagination_tests/page_number.rb +54 -0
  223. data/lib/sink/resources/pagination_tests/page_number_without_current_page_response.rb +55 -0
  224. data/lib/sink/resources/pagination_tests/refs.rb +55 -0
  225. data/lib/sink/resources/pagination_tests/response_headers.rb +34 -0
  226. data/lib/sink/resources/pagination_tests/schema_types.rb +54 -0
  227. data/lib/sink/resources/pagination_tests/top_level_arrays.rb +34 -0
  228. data/lib/sink/resources/pagination_tests.rb +64 -0
  229. data/lib/sink/resources/parent/child.rb +30 -0
  230. data/lib/sink/resources/parent.rb +18 -0
  231. data/lib/sink/resources/path_params.rb +210 -0
  232. data/lib/sink/resources/positional_params.rb +237 -0
  233. data/lib/sink/resources/query_params.rb +166 -0
  234. data/lib/sink/resources/recursion/shared_responses.rb +26 -0
  235. data/lib/sink/resources/recursion.rb +68 -0
  236. data/lib/sink/resources/resource_refs/paginated_model_first_ref.rb +14 -0
  237. data/lib/sink/resources/resource_refs/paginated_model_second_ref.rb +14 -0
  238. data/lib/sink/resources/resource_refs/parent/child.rb +31 -0
  239. data/lib/sink/resources/resource_refs/parent.rb +32 -0
  240. data/lib/sink/resources/resource_refs.rb +24 -0
  241. data/lib/sink/resources/resources.rb +26 -0
  242. data/lib/sink/resources/responses/union_types.rb +98 -0
  243. data/lib/sink/resources/responses.rb +319 -0
  244. data/lib/sink/resources/shared_query_params.rb +48 -0
  245. data/lib/sink/resources/streaming.rb +106 -0
  246. data/lib/sink/resources/testing.rb +24 -0
  247. data/lib/sink/resources/tests.rb +26 -0
  248. data/lib/sink/resources/tools.rb +33 -0
  249. data/lib/sink/resources/types/allofs.rb +14 -0
  250. data/lib/sink/resources/types/arrays.rb +62 -0
  251. data/lib/sink/resources/types/enums.rb +95 -0
  252. data/lib/sink/resources/types/maps.rb +29 -0
  253. data/lib/sink/resources/types/objects.rb +105 -0
  254. data/lib/sink/resources/types/primitives.rb +34 -0
  255. data/lib/sink/resources/types/read_only_params.rb +34 -0
  256. data/lib/sink/resources/types/unions.rb +126 -0
  257. data/lib/sink/resources/types/write_only_responses.rb +28 -0
  258. data/lib/sink/resources/types.rb +95 -0
  259. data/lib/sink/resources/undocumented_resource.rb +47 -0
  260. data/lib/sink/resources/version_1_30_names.rb +41 -0
  261. data/lib/sink/resources/widgets.rb +30 -0
  262. data/lib/sink/util.rb +78 -0
  263. data/lib/sink/version.rb +5 -0
  264. data/lib/sink.rb +276 -0
  265. metadata +322 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b0b3135f8e32ef8791093777d9a9bd263cc2ebeae00c1720ede5f137b49619e1
4
+ data.tar.gz: d0e5de4d073038141ab8c9340ff81c582b021a645dbe5a544145d5d08e2c88a6
5
+ SHA512:
6
+ metadata.gz: ab5b68f79778de0967482cad9b1025353f9dac4fa0f750b5355c90296249b3eaad465c3994eae926a2a8e4750b0551ec496954ddd855ebe6482fee9f18317c0b
7
+ data.tar.gz: 12865e7a6723f2df54e89c011e2b5cd35a671939795d5b39d91d4e8b63d3e33b43d2c31b3bedaf6464e63e0cc42807c604a4072697870519d3a70b560a804312
data/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # Sink Ruby API library
2
+
3
+ The Sink Ruby library provides convenient access to the Sink REST API from any Ruby 3.0+
4
+ application.
5
+
6
+ It is generated with [Stainless](https://www.stainlessapi.com/).
7
+
8
+ ## Documentation
9
+
10
+ Documentation for the most recent version of this gem can be found [on RubyDoc](https://rubydoc.info/github/stainless-sdks/sink-ruby-public).
11
+
12
+ The underlying REST API documentation can be found on [stainlessapi.com](https://stainlessapi.com).
13
+
14
+ ## Installation
15
+
16
+ To use this gem during the beta, install directly from GitHub with Bundler by
17
+ adding the following to your application's `Gemfile`:
18
+
19
+ ```ruby
20
+ gem "sink", git: "https://github.com/stainless-sdks/sink-ruby-public", branch: "main"
21
+ ```
22
+
23
+ To fetch an initial copy of the gem:
24
+
25
+ ```sh
26
+ bundle install
27
+ ```
28
+
29
+ To update the version used by your application when updates are pushed to
30
+ GitHub:
31
+
32
+ ```sh
33
+ bundle update sink
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ```ruby
39
+ require "sink"
40
+
41
+ sink = Sink::Client.new(
42
+ user_token: "My User Token", # defaults to ENV["SINK_CUSTOM_API_KEY_ENV"]
43
+ environment: "sandbox", # defaults to "production"
44
+ username: "Robert",
45
+ some_number_arg_required_no_default: 0,
46
+ some_number_arg_required_no_default_no_env: 0,
47
+ required_arg_no_env: "<example>"
48
+ )
49
+
50
+ card = sink.cards.create(
51
+ type: "SINGLE_USE",
52
+ exp_month: "08",
53
+ not_: "TEST",
54
+ shipping_address: {
55
+ "address1" => "180 Varick St",
56
+ "city" => "New York",
57
+ "country" => "USA",
58
+ "first_name" => "Jason",
59
+ "last_name" => "Mimosa",
60
+ "state" => "NY",
61
+ "postal_code" => "H0H0H0"
62
+ }
63
+ )
64
+
65
+ puts(card.token)
66
+ ```
67
+
68
+ ### Errors
69
+
70
+ When the library is unable to connect to the API, or if the API returns a
71
+ non-success status code (i.e., 4xx or 5xx response), a subclass of
72
+ `Sink::HTTP::Error` will be thrown:
73
+
74
+ ```ruby
75
+ begin
76
+ sink.cards.create(type: "an_incorrect_type")
77
+ rescue Sink::HTTP::Error => e
78
+ puts(e.code) # 400
79
+ end
80
+ ```
81
+
82
+ Error codes are as followed:
83
+
84
+ | Cause | Error Type |
85
+ | ---------------- | -------------------------- |
86
+ | HTTP 400 | `BadRequestError` |
87
+ | HTTP 401 | `AuthenticationError` |
88
+ | HTTP 403 | `PermissionDeniedError` |
89
+ | HTTP 404 | `NotFoundError` |
90
+ | HTTP 409 | `ConflictError` |
91
+ | HTTP 422 | `UnprocessableEntityError` |
92
+ | HTTP 429 | `RateLimitError` |
93
+ | HTTP >=500 | `InternalServerError` |
94
+ | Other HTTP error | `APIStatusError` |
95
+ | Timeout | `APITimeoutError` |
96
+ | Network error | `APIConnectionError` |
97
+
98
+ ### Retries
99
+
100
+ Certain errors will be automatically retried 1 times by default, with a short
101
+ exponential backoff. Connection errors (for example, due to a network
102
+ connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, >=500 Internal errors,
103
+ and timeouts will all be retried by default.
104
+
105
+ You can use the `max_retries` option to configure or disable this:
106
+
107
+ ```ruby
108
+ # Configure the default for all requests:
109
+ sink = Sink::Client.new(
110
+ max_retries: 0, # default is 1
111
+ username: "Robert",
112
+ some_number_arg_required_no_default: 0,
113
+ some_number_arg_required_no_default_no_env: 0,
114
+ required_arg_no_env: "<example>"
115
+ )
116
+
117
+ # Or, configure per-request:
118
+ sink.cards.provision_foo("my card token", digital_wallet: "GOOGLE_PAY", max_retries: 5)
119
+ ```
120
+
121
+ ### Timeouts
122
+
123
+ By default, requests will time out after 60 seconds.
124
+ Timeouts are applied separately to the initial connection and the overall request time,
125
+ so in some cases a request could wait 2\*timeout seconds before it fails.
126
+
127
+ You can use the `timeout` option to configure or disable this:
128
+
129
+ ```ruby
130
+ # Configure the default for all requests:
131
+ sink = Sink::Client.new(
132
+ timeout: nil, # default is 60
133
+ username: "Robert",
134
+ some_number_arg_required_no_default: 0,
135
+ some_number_arg_required_no_default_no_env: 0,
136
+ required_arg_no_env: "<example>"
137
+ )
138
+
139
+ # Or, configure per-request:
140
+ sink.cards.create(type: "DIGITAL", timeout: 5)
141
+ ```
142
+
143
+ ## Versioning
144
+
145
+ This package follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions. As the
146
+ library is in initial development and has a major version of `0`, APIs may change
147
+ at any time.
148
+
149
+ ## Requirements
150
+
151
+ Ruby 3.0 or higher.
@@ -0,0 +1,404 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sink
4
+ # @!visibility private
5
+ class BaseClient
6
+ attr_accessor :requester
7
+
8
+ # @param base_url [String]
9
+ # @param timeout [Integer, nil]
10
+ # @param headers [Hash{String => String}]
11
+ # @param max_retries [Integer]
12
+ # @param idempotency_header [String, nil]
13
+ def initialize(
14
+ base_url:,
15
+ timeout: nil,
16
+ headers: {},
17
+ max_retries: 0,
18
+ idempotency_header: nil
19
+ )
20
+ self.requester = PooledNetRequester.new
21
+ base_url_parsed = URI.parse(base_url)
22
+ @headers = Util.normalized_headers(
23
+ {
24
+ "X-Stainless-Lang" => "ruby",
25
+ "X-Stainless-Package-Version" => Sink::VERSION,
26
+ "X-Stainless-Runtime" => RUBY_ENGINE,
27
+ "X-Stainless-Runtime-Version" => RUBY_ENGINE_VERSION,
28
+ "Accept" => "application/json"
29
+ },
30
+ headers
31
+ )
32
+ @host = base_url_parsed.host
33
+ @scheme = base_url_parsed.scheme
34
+ @port = base_url_parsed.port
35
+ @base_path = self.class.normalize_path(base_url_parsed.path)
36
+ @max_retries = max_retries
37
+ @timeout = timeout
38
+ @idempotency_header = idempotency_header
39
+ end
40
+
41
+ # @return [Hash{String => String}]
42
+ def auth_headers
43
+ {}
44
+ end
45
+
46
+ def validate_request(req, opts)
47
+ if (body = req[:body])
48
+ # Body can be at least a Hash or Array, just check for Hash shape for now.
49
+ if body.is_a?(Hash)
50
+ body.each_key do |k|
51
+ unless k.is_a?(Symbol)
52
+ raise ArgumentError, "Request body keys must be Symbols, got #{k.inspect}"
53
+ end
54
+ end
55
+ end
56
+ end
57
+
58
+ unless opts.is_a?(Hash) || opts.is_a?(Sink::RequestOption)
59
+ raise ArgumentError, "Request `opts` must be a Hash or RequestOptions, got #{opts.inspect}"
60
+ end
61
+ opts.to_h.each_key do |k|
62
+ unless k.is_a?(Symbol)
63
+ raise ArgumentError, "Request `opts` keys must be Symbols, got #{k.inspect}"
64
+ end
65
+ unless (valid_keys = Sink::RequestOptions.options).include?(k)
66
+ raise ArgumentError, "Request `opts` keys must be one of #{valid_keys}, got #{k.inspect}"
67
+ end
68
+ end
69
+ end
70
+
71
+ def self.normalize_path(path)
72
+ path.gsub(/\/+/, "/")
73
+ end
74
+
75
+ def resolve_uri_elements(req)
76
+ from_args =
77
+ if req[:url]
78
+ uri = req[:url].is_a?(URI::Generic) ? req[:url] : URI.parse(req[:url])
79
+ {
80
+ host: uri.host,
81
+ scheme: uri.scheme,
82
+ path: uri.path,
83
+ query: CGI.parse(uri.query || ""),
84
+ port: uri.port
85
+ }
86
+ else
87
+ from_req = req.slice(:host, :scheme, :path, :port, :query)
88
+ from_req[:path] = self.class.normalize_path("/#{@base_path}/#{from_req[:path]}")
89
+ from_req
90
+ end
91
+
92
+ uri_components = {host: @host, scheme: @scheme, port: @port}.merge(from_args)
93
+
94
+ if req[:extra_query]
95
+ uri_components[:query] = Util.deep_merge(uri_components[:query], req[:extra_query], concat: true)
96
+ end
97
+
98
+ uri_components
99
+ end
100
+
101
+ def prep_request(options)
102
+ method = options.fetch(:method)
103
+
104
+ headers = Util.normalized_headers(@headers, auth_headers, options[:headers], options[:extra_headers])
105
+ if @idempotency_header && !headers[@idempotency_header] && ![:get, :head, :options].include?(method)
106
+ headers[@idempotency_header.to_s.downcase] = options[:idempotency_key] || generate_idempotency_key
107
+ end
108
+ if !headers.key?("x-stainless-retry-count")
109
+ headers["x-stainless-retry-count"] = "0"
110
+ end
111
+ headers.compact!
112
+ headers.transform_values!(&:to_s)
113
+
114
+ body =
115
+ case method
116
+ when :post, :put, :patch, :delete
117
+ body = options[:body]
118
+ if body
119
+ if headers["content-type"] == "application/json"
120
+ JSON.dump(body)
121
+ else
122
+ body
123
+ end
124
+ end
125
+ else
126
+ nil
127
+ end
128
+ if options[:extra_body]
129
+ body = Util.deep_merge(body, options[:extra_body])
130
+ end
131
+
132
+ url_elements = resolve_uri_elements(options)
133
+
134
+ {method: method, headers: headers, body: body}.merge(url_elements)
135
+ end
136
+
137
+ def generate_idempotency_key
138
+ "stainless-ruby-retry-#{SecureRandom.uuid}"
139
+ end
140
+
141
+ def should_retry?(response)
142
+ should_retry_header = response["x-should-retry"]
143
+
144
+ case should_retry_header
145
+ when "true"
146
+ true
147
+ when "false"
148
+ false
149
+ else
150
+ response_code = response.code.to_i
151
+ # retry on:
152
+ # 408: timeouts
153
+ # 409: locks
154
+ # 429: rate limits
155
+ # 500+: unknown errors
156
+ [408, 409, 429].include?(response_code) || response_code >= 500
157
+ end
158
+ end
159
+
160
+ def make_status_error(message:, body:, response:)
161
+ raise NotImplementedError
162
+ end
163
+
164
+ def make_status_error_from_response(response)
165
+ err_body =
166
+ begin
167
+ JSON.parse(response.body)
168
+ rescue StandardError
169
+ response
170
+ end
171
+
172
+ # We include the body in the error message as well as returning it
173
+ # since logging error messages is a common and quick way to assess what's
174
+ # wrong with a response.
175
+ message = "Error code: #{response.code}; Response: #{response.body}"
176
+
177
+ make_status_error(message: message, body: err_body, response: response)
178
+ end
179
+
180
+ def header_based_retry(response)
181
+ # Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it.
182
+ retry_after_millis = Float(response["retry-after-ms"], exception: false)
183
+ if retry_after_millis
184
+ retry_after = retry_after_millis / 1000.0
185
+ elsif response["retry-after"]
186
+ retry_after = Float(response["retry-after"], exception: false)
187
+ if retry_after.nil?
188
+ begin
189
+ base = Time.now
190
+ if response["x-stainless-mock-sleep-base"]
191
+ base = Time.httpdate(response["x-stainless-mock-sleep-base"])
192
+ end
193
+ retry_after = Time.httpdate(response["retry-after"]) - base
194
+ rescue StandardError # rubocop:disable Lint/SuppressedException
195
+ end
196
+ end
197
+ end
198
+ retry_after
199
+ rescue StandardError # rubocop:disable Lint/SuppressedException
200
+ end
201
+
202
+ def send_request(request, max_retries:, timeout:, redirect_count:)
203
+ delay = 0.6
204
+ max_delay = 8.0
205
+ # Don't send the current retry count in the headers if the caller modified the header defaults.
206
+ should_send_retry_count = request[:headers]["x-stainless-retry-count"] == "0"
207
+ retries = 0
208
+ loop do # rubocop:disable Metrics/BlockLength
209
+ if should_send_retry_count
210
+ request[:headers]["x-stainless-retry-count"] = retries.to_s
211
+ end
212
+
213
+ begin
214
+ response = @requester.execute(request, timeout: timeout)
215
+ status = response.code.to_i
216
+
217
+ if status < 300
218
+ return response
219
+ elsif status < 400
220
+ begin
221
+ prev_uri = URI.parse(Util.uri_from_req(request, absolute: true))
222
+ location = URI.join(prev_uri, response["location"])
223
+ rescue ArgumentError
224
+ message = "server responded with status #{status} but no valid location header"
225
+ raise HTTP::APIConnectionError.new(message: message, request: request)
226
+ end
227
+ # from whatwg fetch spec
228
+ if redirect_count == 20
229
+ message = "failed to complete the request within 20 redirects"
230
+ raise HTTP::APIConnectionError.new(message: message, request: request)
231
+ end
232
+ if location.scheme != "http" && location.scheme != "https"
233
+ message = "tried to redirect to a non-http URL"
234
+ raise HTTP::APIConnectionError.new(message: message, request: request)
235
+ end
236
+ request = request.merge(resolve_uri_elements({url: location}))
237
+ # from whatwg fetch spec
238
+ if ([301, 302].include?(status) && request[:method] == :post) || (status == 303)
239
+ request[:method] = request[:method] == :head ? :head : :get
240
+ request[:body] = nil
241
+ request[:headers] = request[:headers].reject do |k|
242
+ %w[content-encoding content-language content-location content-type content-length].include?(k)
243
+ end
244
+ end
245
+ # from undici
246
+ if Sink::Util.uri_origin(prev_uri) != Sink::Util.uri_origin(location)
247
+ request[:headers] = request[:headers].reject do |k|
248
+ %w[authorization cookie proxy-authorization host].include?(k)
249
+ end
250
+ end
251
+ return send_request(
252
+ request,
253
+ max_retries: max_retries,
254
+ timeout: timeout,
255
+ redirect_count: redirect_count + 1
256
+ )
257
+ end
258
+ rescue Net::HTTPBadResponse
259
+ if retries >= max_retries
260
+ message = "failed to complete the request within #{max_retries} retries"
261
+ raise HTTP::APIConnectionError.new(message: message, request: request)
262
+ end
263
+ rescue Timeout::Error
264
+ if retries >= max_retries
265
+ message = "failed to complete the request within #{max_retries} retries"
266
+ raise HTTP::APITimeoutError.new(message: message, request: request)
267
+ end
268
+ end
269
+
270
+ if (response && !should_retry?(response)) || retries >= max_retries
271
+ raise make_status_error_from_response(response)
272
+ end
273
+
274
+ retries += 1
275
+ base_delay = header_based_retry(response)
276
+ if base_delay
277
+ delay = base_delay
278
+ else
279
+ base_delay = (delay * (2**retries))
280
+ jitter_factor = 1 - (0.25 * rand)
281
+ delay = (base_delay * jitter_factor).clamp(0, max_delay)
282
+ end
283
+
284
+ if response&.key?("x-stainless-mock-sleep")
285
+ request[:headers]["x-stainless-mock-slept"] = delay
286
+ else
287
+ sleep(delay)
288
+ end
289
+ end
290
+ end
291
+
292
+ # Execute the request specified by req + opts. This is the method that all
293
+ # resource methods call into.
294
+ # Params req & opts are kept separate up until this point so that we can
295
+ # validate opts as it was given to us by the user.
296
+ def request(req, opts)
297
+ validate_request(req, opts)
298
+ options = Util.deep_merge(req, opts)
299
+ request_args = prep_request(options)
300
+ response = send_request(
301
+ request_args,
302
+ max_retries: opts.fetch(:max_retries, @max_retries),
303
+ timeout: opts.fetch(:timeout, @timeout),
304
+ redirect_count: 0
305
+ )
306
+ raw_data =
307
+ case response.content_type
308
+ when "application/json"
309
+ begin
310
+ data = JSON.parse(response.body, symbolize_names: true)
311
+ req[:unwrap] ? data[req[:unwrap]] : data
312
+ rescue JSON::ParserError
313
+ response.body
314
+ end
315
+ # TODO: parsing other response types
316
+ else
317
+ response.body
318
+ end
319
+
320
+ if (page = req[:page])
321
+ model = req.fetch(:model)
322
+ page.new(model, raw_data, response, self, req, opts)
323
+ elsif (model = req[:model])
324
+ Converter.convert(model, raw_data)
325
+ else
326
+ raw_data
327
+ end
328
+ end
329
+
330
+ # @return [String]
331
+ def inspect
332
+ base_url = Util.uri_from_req(
333
+ {host: @host, scheme: @scheme, port: @port, path: @base_path},
334
+ absolute: true
335
+ )
336
+ "#<#{self.class.name}:0x#{object_id.to_s(16)} base_url=#{base_url.inspect} max_retries=#{@max_retries.inspect} timeout=#{@timeout.inspect}>"
337
+ end
338
+ end
339
+
340
+ class Error < StandardError
341
+ end
342
+
343
+ module HTTP
344
+ class Error < Sink::Error
345
+ end
346
+
347
+ class ResponseError < Error
348
+ attr_reader :response, :body
349
+
350
+ # @!attribute [r] code
351
+ # @return [Integer]
352
+ attr_reader :code
353
+
354
+ def initialize(message:, response:, body:)
355
+ super(message)
356
+ @response = response
357
+ @body = body
358
+ @code = response.code.to_i
359
+ end
360
+ end
361
+
362
+ class RequestError < Error
363
+ attr_reader :request
364
+
365
+ def initialize(message:, request:)
366
+ super(message)
367
+ @request = request
368
+ end
369
+ end
370
+
371
+ class BadRequestError < ResponseError
372
+ end
373
+
374
+ class AuthenticationError < ResponseError
375
+ end
376
+
377
+ class PermissionDeniedError < ResponseError
378
+ end
379
+
380
+ class NotFoundError < ResponseError
381
+ end
382
+
383
+ class ConflictError < ResponseError
384
+ end
385
+
386
+ class UnprocessableEntityError < ResponseError
387
+ end
388
+
389
+ class RateLimitError < ResponseError
390
+ end
391
+
392
+ class InternalServerError < ResponseError
393
+ end
394
+
395
+ class APIStatusError < ResponseError
396
+ end
397
+
398
+ class APIConnectionError < RequestError
399
+ end
400
+
401
+ class APITimeoutError < RequestError
402
+ end
403
+ end
404
+ end