test-test-ignore-123123 0.0.1.pre.alpha.0

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