terminal-shop 3.7.0 → 3.8.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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -0
  3. data/README.md +81 -53
  4. data/SECURITY.md +2 -2
  5. data/lib/terminal_shop/client.rb +4 -4
  6. data/lib/terminal_shop/internal/transport/pooled_net_requester.rb +3 -1
  7. data/lib/terminal_shop/internal/type/array_of.rb +8 -0
  8. data/lib/terminal_shop/internal/type/base_model.rb +15 -0
  9. data/lib/terminal_shop/internal/type/boolean.rb +8 -0
  10. data/lib/terminal_shop/internal/type/enum.rb +12 -0
  11. data/lib/terminal_shop/internal/type/file_input.rb +7 -0
  12. data/lib/terminal_shop/internal/type/hash_of.rb +8 -0
  13. data/lib/terminal_shop/internal/type/union.rb +12 -0
  14. data/lib/terminal_shop/internal/type/unknown.rb +8 -0
  15. data/lib/terminal_shop/internal/util.rb +45 -0
  16. data/lib/terminal_shop/internal.rb +3 -0
  17. data/lib/terminal_shop/models/subscription.rb +0 -9
  18. data/lib/terminal_shop/models/subscription_update_params.rb +0 -9
  19. data/lib/terminal_shop/models.rb +30 -19
  20. data/lib/terminal_shop/version.rb +1 -1
  21. data/rbi/terminal_shop/internal/transport/pooled_net_requester.rbi +5 -1
  22. data/rbi/terminal_shop/internal/type/array_of.rbi +6 -0
  23. data/rbi/terminal_shop/internal/type/base_model.rbi +5 -0
  24. data/rbi/terminal_shop/internal/type/boolean.rbi +6 -0
  25. data/rbi/terminal_shop/internal/type/enum.rbi +5 -0
  26. data/rbi/terminal_shop/internal/type/file_input.rbi +5 -0
  27. data/rbi/terminal_shop/internal/type/hash_of.rbi +6 -0
  28. data/rbi/terminal_shop/internal/type/union.rbi +5 -0
  29. data/rbi/terminal_shop/internal/type/unknown.rbi +6 -0
  30. data/rbi/terminal_shop/internal/util.rbi +34 -0
  31. data/rbi/terminal_shop/internal.rbi +5 -0
  32. data/rbi/terminal_shop/models/subscription.rbi +2 -13
  33. data/sig/terminal_shop/internal/transport/pooled_net_requester.rbs +2 -0
  34. data/sig/terminal_shop/internal/type/array_of.rbs +3 -0
  35. data/sig/terminal_shop/internal/type/base_model.rbs +2 -0
  36. data/sig/terminal_shop/internal/type/boolean.rbs +3 -0
  37. data/sig/terminal_shop/internal/type/enum.rbs +2 -0
  38. data/sig/terminal_shop/internal/type/file_input.rbs +2 -0
  39. data/sig/terminal_shop/internal/type/hash_of.rbs +3 -0
  40. data/sig/terminal_shop/internal/type/union.rbs +2 -0
  41. data/sig/terminal_shop/internal/type/unknown.rbs +3 -0
  42. data/sig/terminal_shop/internal/util.rbs +12 -0
  43. data/sig/terminal_shop/internal.rbs +2 -0
  44. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec0b2f09a8009870055d5b2a868a6078adb11504f48eba5eea34b84ff89ba60f
4
- data.tar.gz: f2e9a51a8c54a1eb7f07f40485b89b93218ba1055a8b0498a11f97caa15d5c71
3
+ metadata.gz: '01845ef0b10623ae25a1778177a60981b0edf186dc844b730f99d7cf76b91b99'
4
+ data.tar.gz: 59e7ee0af19ab4dd6ef9d95b54edad958cf89de4fb2e5ce9ba11b23e87509818
5
5
  SHA512:
6
- metadata.gz: 1144da9caada255b1fd2a9856dd8a2d5e6375c0322e369d761289b41c8aa2fe1ba318add613dc0f1cbcd1031badc4576d27084c635921cd063848dbcae5a9ea9
7
- data.tar.gz: e5271523d7d53bcd460ea32453cab3b764009685b290344dcbc07def5ebe9133dd0e8cf55cb3ea72b2491cfb47488c21cdab21c67c0ca4e9b5add53c266ee185
6
+ metadata.gz: 9f1503d288a6b28bce4920c36d9fdd71bf703985b7c7cba6eaeb117d27729cb9ce527b95ed3c8a8705cf5484015026e01a2532f690af7ac74f594f9adf044410
7
+ data.tar.gz: 7af9706e59ebac0b27c713f7d9e93b45867a865423139d7841b0eb655988ff7ced99f3cb6d2dd8bb75f8b15c6057f70ec86f20c2f76f4d73c9bbf67403de20d4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.8.0 (2025-05-22)
4
+
5
+ Full Changelog: [v3.7.0...v3.8.0](https://github.com/terminaldotshop/terminal-sdk-ruby/compare/v3.7.0...v3.8.0)
6
+
7
+ ### Features
8
+
9
+ * bump default connection pool size limit to minimum of 99 ([81feb3e](https://github.com/terminaldotshop/terminal-sdk-ruby/commit/81feb3eb7e2d0c5b1df983647c436ebf966ece2c))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * correctly instantiate sorbet type aliases for enums and unions ([2698489](https://github.com/terminaldotshop/terminal-sdk-ruby/commit/2698489f9f63ced3353196009dc2329e20f8cff5))
15
+
16
+
17
+ ### Chores
18
+
19
+ * **docs:** grammar improvements ([841d9a7](https://github.com/terminaldotshop/terminal-sdk-ruby/commit/841d9a7d18776a55e947cee60233d0756579b22c))
20
+ * **internal:** codegen related update ([68a3efa](https://github.com/terminaldotshop/terminal-sdk-ruby/commit/68a3efaf40e8944faf60b604b5aa33b46c1aedf0))
21
+ * refine Yard and Sorbet types and ensure linting is turned on for examples ([41916e7](https://github.com/terminaldotshop/terminal-sdk-ruby/commit/41916e7b6c195ae8085ac89393b0893b42bf72bc))
22
+ * use sorbet union aliases where available ([046dd18](https://github.com/terminaldotshop/terminal-sdk-ruby/commit/046dd183ff9c9826d45fdcf73a6512effd343ca5))
23
+ * whitespaces ([88c3862](https://github.com/terminaldotshop/terminal-sdk-ruby/commit/88c38620dbdceefd1eb268b457a464a0b59daa6c))
24
+
25
+
26
+ ### Documentation
27
+
28
+ * rewrite much of README.md for readability ([564f4f7](https://github.com/terminaldotshop/terminal-sdk-ruby/commit/564f4f7b65f67c1f4f17f6a06c952a570263d4d1))
29
+
3
30
  ## 3.7.0 (2025-05-14)
4
31
 
5
32
  Full Changelog: [v3.6.2...v3.7.0](https://github.com/terminaldotshop/terminal-sdk-ruby/compare/v3.6.2...v3.7.0)
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Terminal Ruby API library
2
2
 
3
- The Terminal Ruby library provides convenient access to the Terminal REST API from any Ruby 3.2.0+ application.
3
+ The Terminal Ruby library provides convenient access to the Terminal REST API from any Ruby 3.2.0+ application. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [see below](https://github.com/terminaldotshop/terminal-sdk-ruby#Sorbet) for usage with Sorbet. The standard library's `net/http` is used as the HTTP transport, with connection pooling via the `connection_pool` gem.
4
4
 
5
5
  It is generated with [Stainless](https://www.stainless.com/).
6
6
 
@@ -17,7 +17,7 @@ To use this gem, install via Bundler by adding the following to your application
17
17
  <!-- x-release-please-start-version -->
18
18
 
19
19
  ```ruby
20
- gem "terminal-shop", "~> 3.7.0"
20
+ gem "terminal-shop", "~> 3.8.0"
21
21
  ```
22
22
 
23
23
  <!-- x-release-please-end -->
@@ -38,25 +38,21 @@ products = terminal.product.list
38
38
  puts(products.data)
39
39
  ```
40
40
 
41
- ## Sorbet
42
-
43
- This library is written with [Sorbet type definitions](https://sorbet.org/docs/rbi). However, there is no runtime dependency on the `sorbet-runtime`.
44
-
45
- When using sorbet, it is recommended to use model classes as below. This provides stronger type checking and tooling integration.
46
-
47
- ```ruby
48
- terminal.product.list
49
- ```
50
-
51
- ### Errors
41
+ ### Handling errors
52
42
 
53
43
  When the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of `TerminalShop::Errors::APIError` will be thrown:
54
44
 
55
45
  ```ruby
56
46
  begin
57
47
  product = terminal.product.list
58
- rescue TerminalShop::Errors::APIError => e
59
- puts(e.status) # 400
48
+ rescue TerminalShop::Errors::APIConnectionError => e
49
+ puts("The server could not be reached")
50
+ puts(e.cause) # an underlying Exception, likely raised within `net/http`
51
+ rescue TerminalShop::Errors::RateLimitError => e
52
+ puts("A 429 status code was received; we should back off a bit.")
53
+ rescue TerminalShop::Errors::APIStatusError => e
54
+ puts("Another non-200-range status code was received")
55
+ puts(e.status)
60
56
  end
61
57
  ```
62
58
 
@@ -96,11 +92,7 @@ terminal.product.list(request_options: {max_retries: 5})
96
92
 
97
93
  ### Timeouts
98
94
 
99
- By default, requests will time out after 60 seconds.
100
-
101
- Timeouts are applied separately to the initial connection and the overall request time, so in some cases a request could wait 2\*timeout seconds before it fails.
102
-
103
- You can use the `timeout` option to configure or disable this:
95
+ By default, requests will time out after 60 seconds. You can use the timeout option to configure or disable this:
104
96
 
105
97
  ```ruby
106
98
  # Configure the default for all requests:
@@ -112,39 +104,52 @@ terminal = TerminalShop::Client.new(
112
104
  terminal.product.list(request_options: {timeout: 5})
113
105
  ```
114
106
 
115
- ## Model DSL
107
+ On timeout, `TerminalShop::Errors::APITimeoutError` is raised.
116
108
 
117
- This library uses a simple DSL to represent request parameters and response shapes in `lib/terminal_shop/models`.
109
+ Note that requests that time out are retried by default.
118
110
 
119
- With the right [editor plugins](https://shopify.github.io/ruby-lsp), you can ctrl-click on elements of the DSL to navigate around and explore the library.
111
+ ## Advanced concepts
120
112
 
121
- In all places where a `BaseModel` type is specified, vanilla Ruby `Hash` can also be used. For example, the following are interchangeable as arguments:
113
+ ### BaseModel
122
114
 
123
- ```ruby
124
- # This has tooling readability, for auto-completion, static analysis, and goto definition with supported language services
125
- params = TerminalShop::Models::ProductListParams.new
115
+ All parameter and response objects inherit from `TerminalShop::Internal::Type::BaseModel`, which provides several conveniences, including:
126
116
 
127
- # This also works
128
- params = {
117
+ 1. All fields, including unknown ones, are accessible with `obj[:prop]` syntax, and can be destructured with `obj => {prop: prop}` or pattern-matching syntax.
129
118
 
130
- }
131
- ```
119
+ 2. Structural equivalence for equality; if two API calls return the same values, comparing the responses with == will return true.
132
120
 
133
- ## Editor support
121
+ 3. Both instances and the classes themselves can be pretty-printed.
134
122
 
135
- A combination of [Shopify LSP](https://shopify.github.io/ruby-lsp) and [Solargraph](https://solargraph.org/) is recommended for non-[Sorbet](https://sorbet.org) users. The former is especially good at go to definition, while the latter has much better auto-completion support.
123
+ 4. Helpers such as `#to_h`, `#deep_to_h`, `#to_json`, and `#to_yaml`.
136
124
 
137
- ## Advanced concepts
125
+ ### Making custom or undocumented requests
126
+
127
+ #### Undocumented properties
138
128
 
139
- ### Making custom/undocumented requests
129
+ You can send undocumented parameters to any endpoint, and read undocumented response properties, like so:
130
+
131
+ Note: the `extra_` parameters of the same name overrides the documented parameters.
132
+
133
+ ```ruby
134
+ products =
135
+ terminal.product.list(
136
+ request_options: {
137
+ extra_query: {my_query_parameter: value},
138
+ extra_body: {my_body_parameter: value},
139
+ extra_headers: {"my-header": value}
140
+ }
141
+ )
142
+
143
+ puts(products[:my_undocumented_property])
144
+ ```
140
145
 
141
146
  #### Undocumented request params
142
147
 
143
- If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` under the `request_options:` parameter when making a requests as seen in examples above.
148
+ If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` under the `request_options:` parameter when making a request, as seen in the examples above.
144
149
 
145
150
  #### Undocumented endpoints
146
151
 
147
- To make requests to undocumented endpoints, you can make requests using `client.request`. Options on the client will be respected (such as retries) when making this request.
152
+ To make requests to undocumented endpoints while retaining the benefit of auth, retries, and so on, you can make requests using `client.request`, like so:
148
153
 
149
154
  ```ruby
150
155
  response = client.request(
@@ -152,42 +157,65 @@ response = client.request(
152
157
  path: '/undocumented/endpoint',
153
158
  query: {"dog": "woof"},
154
159
  headers: {"useful-header": "interesting-value"},
155
- body: {"he": "llo"},
160
+ body: {"hello": "world"}
156
161
  )
157
162
  ```
158
163
 
159
164
  ### Concurrency & connection pooling
160
165
 
161
- The `TerminalShop::Client` instances are thread-safe, and should be re-used across multiple threads. By default, each `Client` have their own HTTP connection pool, with a maximum number of connections equal to thread count.
166
+ The `TerminalShop::Client` instances are threadsafe, but are only are fork-safe when there are no in-flight HTTP requests.
162
167
 
163
- When the maximum number of connections has been checked out from the connection pool, the `Client` will wait for an in use connection to become available. The queue time for this mechanism is accounted for by the per-request timeout.
168
+ Each instance of `TerminalShop::Client` has its own HTTP connection pool with a default size of 99. As such, we recommend instantiating the client once per application in most settings.
169
+
170
+ When all available connections from the pool are checked out, requests wait for a new connection to become available, with queue time counting towards the request timeout.
164
171
 
165
172
  Unless otherwise specified, other classes in the SDK do not have locks protecting their underlying data structure.
166
173
 
167
- Currently, `TerminalShop::Client` instances are only fork-safe if there are no in-flight HTTP requests.
174
+ ## Sorbet
168
175
 
169
- ### Sorbet
176
+ This library provides comprehensive [RBI](https://sorbet.org/docs/rbi) definitions, and has no dependency on sorbet-runtime.
170
177
 
171
- #### Enums
178
+ You can provide typesafe request parameters like so:
172
179
 
173
- Sorbet's typed enums require sub-classing of the [`T::Enum` class](https://sorbet.org/docs/tenum) from the `sorbet-runtime` gem.
180
+ ```ruby
181
+ terminal.product.list
182
+ ```
174
183
 
175
- Since this library does not depend on `sorbet-runtime`, it uses a [`T.all` intersection type](https://sorbet.org/docs/intersection-types) with a ruby primitive type to construct a "tagged alias" instead.
184
+ Or, equivalently:
176
185
 
177
186
  ```ruby
178
- module TerminalShop::Region
179
- # This alias aids language service driven navigation.
180
- TaggedSymbol = T.type_alias { T.all(Symbol, TerminalShop::Region) }
181
- end
187
+ # Hashes work, but are not typesafe:
188
+ terminal.product.list
189
+
190
+ # You can also splat a full Params class:
191
+ params = TerminalShop::ProductListParams.new
192
+ terminal.product.list(**params)
182
193
  ```
183
194
 
184
- #### Argument passing trick
195
+ ### Enums
185
196
 
186
- It is possible to pass a compatible model / parameter class to a method that expects keyword arguments by using the `**` splat operator.
197
+ Since this library does not depend on `sorbet-runtime`, it cannot provide [`T::Enum`](https://sorbet.org/docs/tenum) instances. Instead, we provide "tagged symbols" instead, which is always a primitive at runtime:
187
198
 
188
199
  ```ruby
189
- params = TerminalShop::Models::ProductListParams.new
190
- terminal.product.list(**params)
200
+ # :allowed
201
+ puts(TerminalShop::ProductAPI::Subscription::ALLOWED)
202
+
203
+ # Revealed type: `T.all(TerminalShop::ProductAPI::Subscription, Symbol)`
204
+ T.reveal_type(TerminalShop::ProductAPI::Subscription::ALLOWED)
205
+ ```
206
+
207
+ Enum parameters have a "relaxed" type, so you can either pass in enum constants or their literal value:
208
+
209
+ ```ruby
210
+ TerminalShop::ProductAPI.new(
211
+ subscription: TerminalShop::ProductAPI::Subscription::ALLOWED,
212
+ # …
213
+ )
214
+
215
+ TerminalShop::ProductAPI.new(
216
+ subscription: :allowed,
217
+ # …
218
+ )
191
219
  ```
192
220
 
193
221
  ## Versioning
data/SECURITY.md CHANGED
@@ -16,11 +16,11 @@ before making any information public.
16
16
  ## Reporting Non-SDK Related Security Issues
17
17
 
18
18
  If you encounter security issues that are not directly related to SDKs but pertain to the services
19
- or products provided by Terminal please follow the respective company's security reporting guidelines.
19
+ or products provided by Terminal, please follow the respective company's security reporting guidelines.
20
20
 
21
21
  ### Terminal Terms and Policies
22
22
 
23
- Please contact dev@terminal.com for any questions or concerns regarding security of our services.
23
+ Please contact dev@terminal.com for any questions or concerns regarding the security of our services.
24
24
 
25
25
  ---
26
26
 
@@ -96,10 +96,10 @@ module TerminalShop
96
96
  app_id: nil,
97
97
  environment: nil,
98
98
  base_url: ENV["TERMINAL_BASE_URL"],
99
- max_retries: TerminalShop::Client::DEFAULT_MAX_RETRIES,
100
- timeout: TerminalShop::Client::DEFAULT_TIMEOUT_IN_SECONDS,
101
- initial_retry_delay: TerminalShop::Client::DEFAULT_INITIAL_RETRY_DELAY,
102
- max_retry_delay: TerminalShop::Client::DEFAULT_MAX_RETRY_DELAY
99
+ max_retries: self.class::DEFAULT_MAX_RETRIES,
100
+ timeout: self.class::DEFAULT_TIMEOUT_IN_SECONDS,
101
+ initial_retry_delay: self.class::DEFAULT_INITIAL_RETRY_DELAY,
102
+ max_retry_delay: self.class::DEFAULT_MAX_RETRY_DELAY
103
103
  )
104
104
  base_url ||= TerminalShop::Client::ENVIRONMENTS.fetch(environment&.to_sym || :production) do
105
105
  message = "environment must be one of #{TerminalShop::Client::ENVIRONMENTS.keys}, got #{environment}"
@@ -11,6 +11,8 @@ module TerminalShop
11
11
  # https://github.com/golang/go/blob/c8eced8580028328fde7c03cbfcb720ce15b2358/src/net/http/transport.go#L49
12
12
  KEEP_ALIVE_TIMEOUT = 30
13
13
 
14
+ DEFAULT_MAX_CONNECTIONS = [Etc.nprocessors, 99].max
15
+
14
16
  class << self
15
17
  # @api private
16
18
  #
@@ -184,7 +186,7 @@ module TerminalShop
184
186
  # @api private
185
187
  #
186
188
  # @param size [Integer]
187
- def initialize(size: Etc.nprocessors)
189
+ def initialize(size: self.class::DEFAULT_MAX_CONNECTIONS)
188
190
  @mutex = Mutex.new
189
191
  @size = size
190
192
  @pools = {}
@@ -12,6 +12,7 @@ module TerminalShop
12
12
  # Array of items of a given type.
13
13
  class ArrayOf
14
14
  include TerminalShop::Internal::Type::Converter
15
+ include TerminalShop::Internal::Util::SorbetRuntimeSupport
15
16
 
16
17
  private_class_method :new
17
18
 
@@ -110,6 +111,13 @@ module TerminalShop
110
111
  end
111
112
  end
112
113
 
114
+ # @api private
115
+ #
116
+ # @return [Object]
117
+ def to_sorbet_type
118
+ T::Array[TerminalShop::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(item_type)]
119
+ end
120
+
113
121
  # @api private
114
122
  #
115
123
  # @return [generic<Elem>]
@@ -309,6 +309,13 @@ module TerminalShop
309
309
 
310
310
  acc
311
311
  end
312
+
313
+ # @api private
314
+ #
315
+ # @return [Object]
316
+ def to_sorbet_type
317
+ self
318
+ end
312
319
  end
313
320
 
314
321
  class << self
@@ -391,6 +398,14 @@ module TerminalShop
391
398
  # @param keys [Array<Symbol>, nil]
392
399
  #
393
400
  # @return [Hash{Symbol=>Object}]
401
+ #
402
+ # @example
403
+ # # `product_api` is a `TerminalShop::ProductAPI`
404
+ # product_api => {
405
+ # id: id,
406
+ # description: description,
407
+ # name: name
408
+ # }
394
409
  def deconstruct_keys(keys)
395
410
  (keys || self.class.known_fields.keys)
396
411
  .filter_map do |k|
@@ -10,6 +10,7 @@ module TerminalShop
10
10
  # Ruby has no Boolean class; this is something for models to refer to.
11
11
  class Boolean
12
12
  extend TerminalShop::Internal::Type::Converter
13
+ extend TerminalShop::Internal::Util::SorbetRuntimeSupport
13
14
 
14
15
  private_class_method :new
15
16
 
@@ -56,6 +57,13 @@ module TerminalShop
56
57
  # @option state [Boolean] :can_retry
57
58
  #
58
59
  # @return [Boolean, Object]
60
+
61
+ # @api private
62
+ #
63
+ # @return [Object]
64
+ def to_sorbet_type
65
+ T::Boolean
66
+ end
59
67
  end
60
68
  end
61
69
  end
@@ -112,6 +112,18 @@ module TerminalShop
112
112
  #
113
113
  # @return [Symbol, Object]
114
114
 
115
+ # @api private
116
+ #
117
+ # @return [Object]
118
+ def to_sorbet_type
119
+ case values
120
+ in []
121
+ T.noreturn
122
+ in [value, *_]
123
+ T.all(TerminalShop::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(value), self)
124
+ end
125
+ end
126
+
115
127
  # @api private
116
128
  #
117
129
  # @param depth [Integer]
@@ -89,6 +89,13 @@ module TerminalShop
89
89
 
90
90
  value
91
91
  end
92
+
93
+ # @api private
94
+ #
95
+ # @return [Object]
96
+ def to_sorbet_type
97
+ T.any(Pathname, StringIO, IO, String, TerminalShop::FilePart)
98
+ end
92
99
  end
93
100
  end
94
101
  end
@@ -12,6 +12,7 @@ module TerminalShop
12
12
  # Hash of items of a given type.
13
13
  class HashOf
14
14
  include TerminalShop::Internal::Type::Converter
15
+ include TerminalShop::Internal::Util::SorbetRuntimeSupport
15
16
 
16
17
  private_class_method :new
17
18
 
@@ -130,6 +131,13 @@ module TerminalShop
130
131
  end
131
132
  end
132
133
 
134
+ # @api private
135
+ #
136
+ # @return [Object]
137
+ def to_sorbet_type
138
+ T::Hash[TerminalShop::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(item_type)]
139
+ end
140
+
133
141
  # @api private
134
142
  #
135
143
  # @return [generic<Elem>]
@@ -197,6 +197,18 @@ module TerminalShop
197
197
  super
198
198
  end
199
199
 
200
+ # @api private
201
+ #
202
+ # @return [Object]
203
+ def to_sorbet_type
204
+ case (v = variants)
205
+ in []
206
+ T.noreturn
207
+ else
208
+ T.any(*v.map { TerminalShop::Internal::Util::SorbetRuntimeSupport.to_sorbet_type(_1) })
209
+ end
210
+ end
211
+
200
212
  # rubocop:enable Style/CaseEquality
201
213
  # rubocop:enable Style/HashEachMethods
202
214
 
@@ -10,6 +10,7 @@ module TerminalShop
10
10
  # When we don't know what to expect for the value.
11
11
  class Unknown
12
12
  extend TerminalShop::Internal::Type::Converter
13
+ extend TerminalShop::Internal::Util::SorbetRuntimeSupport
13
14
 
14
15
  # rubocop:disable Lint/UnusedMethodArgument
15
16
 
@@ -58,6 +59,13 @@ module TerminalShop
58
59
  # @option state [Boolean] :can_retry
59
60
  #
60
61
  # @return [Object]
62
+
63
+ # @api private
64
+ #
65
+ # @return [Object]
66
+ def to_sorbet_type
67
+ T.anything
68
+ end
61
69
  end
62
70
 
63
71
  # rubocop:enable Lint/UnusedMethodArgument
@@ -9,6 +9,23 @@ module TerminalShop
9
9
  # @return [Float]
10
10
  def self.monotonic_secs = Process.clock_gettime(Process::CLOCK_MONOTONIC)
11
11
 
12
+ # @api private
13
+ #
14
+ # @param ns [Module, Class]
15
+ #
16
+ # @return [Enumerable<Module, Class>]
17
+ def self.walk_namespaces(ns)
18
+ ns.constants(false).lazy.flat_map do
19
+ case (c = ns.const_get(_1, false))
20
+ in Module | Class
21
+ walk_namespaces(c)
22
+ else
23
+ []
24
+ end
25
+ end
26
+ .chain([ns])
27
+ end
28
+
12
29
  class << self
13
30
  # @api private
14
31
  #
@@ -826,11 +843,39 @@ module TerminalShop
826
843
  sorbet_runtime_constants.fetch(name).call
827
844
  end
828
845
 
846
+ # @api private
847
+ #
848
+ # @param name [Symbol]
849
+ #
850
+ # @return [Boolean]
851
+ def sorbet_constant_defined?(name) = sorbet_runtime_constants.key?(name)
852
+
829
853
  # @api private
830
854
  #
831
855
  # @param name [Symbol]
832
856
  # @param blk [Proc]
833
857
  def define_sorbet_constant!(name, &blk) = sorbet_runtime_constants.store(name, blk)
858
+
859
+ # @api private
860
+ #
861
+ # @return [Object]
862
+ def to_sorbet_type = raise NotImplementedError
863
+
864
+ class << self
865
+ # @api private
866
+ #
867
+ # @param type [TerminalShop::Internal::Util::SorbetRuntimeSupport, Object]
868
+ #
869
+ # @return [Object]
870
+ def to_sorbet_type(type)
871
+ case type
872
+ in TerminalShop::Internal::Util::SorbetRuntimeSupport
873
+ type.to_sorbet_type
874
+ else
875
+ type
876
+ end
877
+ end
878
+ end
834
879
  end
835
880
 
836
881
  extend TerminalShop::Internal::Util::SorbetRuntimeSupport
@@ -13,5 +13,8 @@ module TerminalShop
13
13
  define_sorbet_constant!(:AnyHash) do
14
14
  T.type_alias { T::Hash[Symbol, T.anything] }
15
15
  end
16
+ define_sorbet_constant!(:FileInput) do
17
+ T.type_alias { T.any(Pathname, StringIO, IO, String, TerminalShop::FilePart) }
18
+ end
16
19
  end
17
20
  end
@@ -119,15 +119,6 @@ module TerminalShop
119
119
 
120
120
  # @!method self.variants
121
121
  # @return [Array(TerminalShop::SubscriptionAPI::Schedule::Fixed, TerminalShop::SubscriptionAPI::Schedule::Weekly)]
122
-
123
- define_sorbet_constant!(:Variants) do
124
- T.type_alias do
125
- T.any(
126
- TerminalShop::SubscriptionAPI::Schedule::Fixed,
127
- TerminalShop::SubscriptionAPI::Schedule::Weekly
128
- )
129
- end
130
- end
131
122
  end
132
123
  end
133
124
  end
@@ -70,15 +70,6 @@ module TerminalShop
70
70
 
71
71
  # @!method self.variants
72
72
  # @return [Array(TerminalShop::SubscriptionUpdateParams::Schedule::Fixed, TerminalShop::SubscriptionUpdateParams::Schedule::Weekly)]
73
-
74
- define_sorbet_constant!(:Variants) do
75
- T.type_alias do
76
- T.any(
77
- TerminalShop::SubscriptionUpdateParams::Schedule::Fixed,
78
- TerminalShop::SubscriptionUpdateParams::Schedule::Weekly
79
- )
80
- end
81
- end
82
73
  end
83
74
  end
84
75
  end
@@ -5,29 +5,40 @@ module TerminalShop
5
5
  cls.define_sorbet_constant!(:OrHash) { T.type_alias { T.any(cls, TerminalShop::Internal::AnyHash) } }
6
6
  end
7
7
 
8
- [
9
- *TerminalShop::Internal::Type::Enum.included_modules,
10
- *TerminalShop::Internal::Type::Union.included_modules
11
- ].each do |cls|
12
- cls.constants.each do |name|
13
- case cls.const_get(name)
14
- in true | false
15
- cls.define_sorbet_constant!(:TaggedBoolean) { T.type_alias { T.all(T::Boolean, cls) } }
16
- cls.define_sorbet_constant!(:OrBoolean) { T.type_alias { T::Boolean } }
17
- in Integer
18
- cls.define_sorbet_constant!(:TaggedInteger) { T.type_alias { T.all(Integer, cls) } }
19
- cls.define_sorbet_constant!(:OrInteger) { T.type_alias { Integer } }
20
- in Float
21
- cls.define_sorbet_constant!(:TaggedFloat) { T.type_alias { T.all(Float, cls) } }
22
- cls.define_sorbet_constant!(:OrFloat) { T.type_alias { Float } }
23
- in Symbol
24
- cls.define_sorbet_constant!(:TaggedSymbol) { T.type_alias { T.all(Symbol, cls) } }
25
- cls.define_sorbet_constant!(:OrSymbol) { T.type_alias { T.any(Symbol, String) } }
26
- else
8
+ TerminalShop::Internal::Util.walk_namespaces(TerminalShop::Models).each do |mod|
9
+ case mod
10
+ in TerminalShop::Internal::Type::Enum | TerminalShop::Internal::Type::Union
11
+ mod.constants.each do |name|
12
+ case mod.const_get(name)
13
+ in true | false
14
+ mod.define_sorbet_constant!(:TaggedBoolean) { T.type_alias { T.all(T::Boolean, mod) } }
15
+ mod.define_sorbet_constant!(:OrBoolean) { T.type_alias { T::Boolean } }
16
+ in Integer
17
+ mod.define_sorbet_constant!(:TaggedInteger) { T.type_alias { T.all(Integer, mod) } }
18
+ mod.define_sorbet_constant!(:OrInteger) { T.type_alias { Integer } }
19
+ in Float
20
+ mod.define_sorbet_constant!(:TaggedFloat) { T.type_alias { T.all(Float, mod) } }
21
+ mod.define_sorbet_constant!(:OrFloat) { T.type_alias { Float } }
22
+ in Symbol
23
+ mod.define_sorbet_constant!(:TaggedSymbol) { T.type_alias { T.all(Symbol, mod) } }
24
+ mod.define_sorbet_constant!(:OrSymbol) { T.type_alias { T.any(Symbol, String) } }
25
+ else
26
+ end
27
27
  end
28
+ else
28
29
  end
29
30
  end
30
31
 
32
+ TerminalShop::Internal::Util.walk_namespaces(TerminalShop::Models)
33
+ .lazy
34
+ .grep(TerminalShop::Internal::Type::Union)
35
+ .each do |mod|
36
+ const = :Variants
37
+ next if mod.sorbet_constant_defined?(const)
38
+
39
+ mod.define_sorbet_constant!(const) { T.type_alias { mod.to_sorbet_type } }
40
+ end
41
+
31
42
  AddressAPI = TerminalShop::Models::AddressAPI
32
43
 
33
44
  AddressCreateParams = TerminalShop::Models::AddressCreateParams
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module TerminalShop
4
- VERSION = "3.7.0"
4
+ VERSION = "3.8.0"
5
5
  end
@@ -22,6 +22,8 @@ module TerminalShop
22
22
  # https://github.com/golang/go/blob/c8eced8580028328fde7c03cbfcb720ce15b2358/src/net/http/transport.go#L49
23
23
  KEEP_ALIVE_TIMEOUT = 30
24
24
 
25
+ DEFAULT_MAX_CONNECTIONS = T.let(T.unsafe(nil), Integer)
26
+
25
27
  class << self
26
28
  # @api private
27
29
  sig { params(url: URI::Generic).returns(Net::HTTP) }
@@ -68,7 +70,9 @@ module TerminalShop
68
70
 
69
71
  # @api private
70
72
  sig { params(size: Integer).returns(T.attached_class) }
71
- def self.new(size: Etc.nprocessors)
73
+ def self.new(
74
+ size: TerminalShop::Internal::Transport::PooledNetRequester::DEFAULT_MAX_CONNECTIONS
75
+ )
72
76
  end
73
77
  end
74
78
  end
@@ -8,6 +8,7 @@ module TerminalShop
8
8
  # Array of items of a given type.
9
9
  class ArrayOf
10
10
  include TerminalShop::Internal::Type::Converter
11
+ include TerminalShop::Internal::Util::SorbetRuntimeSupport
11
12
 
12
13
  abstract!
13
14
 
@@ -63,6 +64,11 @@ module TerminalShop
63
64
  def dump(value, state:)
64
65
  end
65
66
 
67
+ # @api private
68
+ sig { returns(T.anything) }
69
+ def to_sorbet_type
70
+ end
71
+
66
72
  # @api private
67
73
  sig { returns(Elem) }
68
74
  protected def item_type
@@ -205,6 +205,11 @@ module TerminalShop
205
205
  end
206
206
  def dump(value, state:)
207
207
  end
208
+
209
+ # @api private
210
+ sig { returns(T.anything) }
211
+ def to_sorbet_type
212
+ end
208
213
  end
209
214
 
210
215
  class << self
@@ -8,6 +8,7 @@ module TerminalShop
8
8
  # Ruby has no Boolean class; this is something for models to refer to.
9
9
  class Boolean
10
10
  extend TerminalShop::Internal::Type::Converter
11
+ extend TerminalShop::Internal::Util::SorbetRuntimeSupport
11
12
 
12
13
  abstract!
13
14
 
@@ -43,6 +44,11 @@ module TerminalShop
43
44
  end
44
45
  def dump(value, state:)
45
46
  end
47
+
48
+ # @api private
49
+ sig { returns(T.anything) }
50
+ def to_sorbet_type
51
+ end
46
52
  end
47
53
  end
48
54
  end
@@ -67,6 +67,11 @@ module TerminalShop
67
67
  def dump(value, state:)
68
68
  end
69
69
 
70
+ # @api private
71
+ sig { returns(T.anything) }
72
+ def to_sorbet_type
73
+ end
74
+
70
75
  # @api private
71
76
  sig { params(depth: Integer).returns(String) }
72
77
  def inspect(depth: 0)
@@ -47,6 +47,11 @@ module TerminalShop
47
47
  end
48
48
  def dump(value, state:)
49
49
  end
50
+
51
+ # @api private
52
+ sig { returns(T.anything) }
53
+ def to_sorbet_type
54
+ end
50
55
  end
51
56
  end
52
57
  end
@@ -8,6 +8,7 @@ module TerminalShop
8
8
  # Hash of items of a given type.
9
9
  class HashOf
10
10
  include TerminalShop::Internal::Type::Converter
11
+ include TerminalShop::Internal::Util::SorbetRuntimeSupport
11
12
 
12
13
  abstract!
13
14
 
@@ -63,6 +64,11 @@ module TerminalShop
63
64
  def dump(value, state:)
64
65
  end
65
66
 
67
+ # @api private
68
+ sig { returns(T.anything) }
69
+ def to_sorbet_type
70
+ end
71
+
66
72
  # @api private
67
73
  sig { returns(Elem) }
68
74
  protected def item_type
@@ -101,6 +101,11 @@ module TerminalShop
101
101
  def dump(value, state:)
102
102
  end
103
103
 
104
+ # @api private
105
+ sig { returns(T.anything) }
106
+ def to_sorbet_type
107
+ end
108
+
104
109
  # @api private
105
110
  sig { params(depth: Integer).returns(String) }
106
111
  def inspect(depth: 0)
@@ -8,6 +8,7 @@ module TerminalShop
8
8
  # When we don't know what to expect for the value.
9
9
  class Unknown
10
10
  extend TerminalShop::Internal::Type::Converter
11
+ extend TerminalShop::Internal::Util::SorbetRuntimeSupport
11
12
 
12
13
  abstract!
13
14
 
@@ -43,6 +44,11 @@ module TerminalShop
43
44
  end
44
45
  def dump(value, state:)
45
46
  end
47
+
48
+ # @api private
49
+ sig { returns(T.anything) }
50
+ def to_sorbet_type
51
+ end
46
52
  end
47
53
  end
48
54
  end
@@ -11,6 +11,15 @@ module TerminalShop
11
11
  def self.monotonic_secs
12
12
  end
13
13
 
14
+ # @api private
15
+ sig do
16
+ params(ns: T.any(Module, T::Class[T.anything])).returns(
17
+ T::Enumerable[T.any(Module, T::Class[T.anything])]
18
+ )
19
+ end
20
+ def self.walk_namespaces(ns)
21
+ end
22
+
14
23
  class << self
15
24
  # @api private
16
25
  sig { returns(String) }
@@ -441,10 +450,35 @@ module TerminalShop
441
450
  def const_missing(name)
442
451
  end
443
452
 
453
+ # @api private
454
+ sig { params(name: Symbol).returns(T::Boolean) }
455
+ def sorbet_constant_defined?(name)
456
+ end
457
+
444
458
  # @api private
445
459
  sig { params(name: Symbol, blk: T.proc.returns(T.anything)).void }
446
460
  def define_sorbet_constant!(name, &blk)
447
461
  end
462
+
463
+ # @api private
464
+ sig { returns(T.anything) }
465
+ def to_sorbet_type
466
+ end
467
+
468
+ class << self
469
+ # @api private
470
+ sig do
471
+ params(
472
+ type:
473
+ T.any(
474
+ TerminalShop::Internal::Util::SorbetRuntimeSupport,
475
+ T.anything
476
+ )
477
+ ).returns(T.anything)
478
+ end
479
+ def to_sorbet_type(type)
480
+ end
481
+ end
448
482
  end
449
483
  end
450
484
  end
@@ -8,6 +8,11 @@ module TerminalShop
8
8
  # this alias might be refined in the future.
9
9
  AnyHash = T.type_alias { T::Hash[Symbol, T.anything] }
10
10
 
11
+ FileInput =
12
+ T.type_alias do
13
+ T.any(Pathname, StringIO, IO, String, TerminalShop::FilePart)
14
+ end
15
+
11
16
  OMIT = T.let(Object.new.freeze, T.anything)
12
17
  end
13
18
  end
@@ -45,14 +45,7 @@ module TerminalShop
45
45
 
46
46
  # Schedule of the subscription.
47
47
  sig do
48
- returns(
49
- T.nilable(
50
- T.any(
51
- TerminalShop::SubscriptionAPI::Schedule::Fixed,
52
- TerminalShop::SubscriptionAPI::Schedule::Weekly
53
- )
54
- )
55
- )
48
+ returns(T.nilable(TerminalShop::SubscriptionAPI::Schedule::Variants))
56
49
  end
57
50
  attr_reader :schedule
58
51
 
@@ -118,11 +111,7 @@ module TerminalShop
118
111
  product_variant_id: String,
119
112
  quantity: Integer,
120
113
  next_: String,
121
- schedule:
122
- T.any(
123
- TerminalShop::SubscriptionAPI::Schedule::Fixed,
124
- TerminalShop::SubscriptionAPI::Schedule::Weekly
125
- )
114
+ schedule: TerminalShop::SubscriptionAPI::Schedule::Variants
126
115
  }
127
116
  )
128
117
  end
@@ -15,6 +15,8 @@ module TerminalShop
15
15
 
16
16
  KEEP_ALIVE_TIMEOUT: 30
17
17
 
18
+ DEFAULT_MAX_CONNECTIONS: Integer
19
+
18
20
  def self.connect: (URI::Generic url) -> top
19
21
 
20
22
  def self.calibrate_socket_timeout: (top conn, Float deadline) -> void
@@ -3,6 +3,7 @@ module TerminalShop
3
3
  module Type
4
4
  class ArrayOf[Elem]
5
5
  include TerminalShop::Internal::Type::Converter
6
+ include TerminalShop::Internal::Util::SorbetRuntimeSupport
6
7
 
7
8
  def self.[]: (
8
9
  ::Hash[Symbol, top]
@@ -27,6 +28,8 @@ module TerminalShop
27
28
  state: TerminalShop::Internal::Type::Converter::dump_state
28
29
  ) -> (::Array[top] | top)
29
30
 
31
+ def to_sorbet_type: -> top
32
+
30
33
  def item_type: -> Elem
31
34
 
32
35
  def nilable?: -> bool
@@ -70,6 +70,8 @@ module TerminalShop
70
70
  state: TerminalShop::Internal::Type::Converter::dump_state
71
71
  ) -> (::Hash[top, top] | top)
72
72
 
73
+ def self.to_sorbet_type: -> top
74
+
73
75
  def self.recursively_to_h: (
74
76
  TerminalShop::Internal::Type::BaseModel model,
75
77
  convert: bool
@@ -3,6 +3,7 @@ module TerminalShop
3
3
  module Type
4
4
  class Boolean
5
5
  extend TerminalShop::Internal::Type::Converter
6
+ extend TerminalShop::Internal::Util::SorbetRuntimeSupport
6
7
 
7
8
  def self.===: (top other) -> bool
8
9
 
@@ -17,6 +18,8 @@ module TerminalShop
17
18
  bool | top value,
18
19
  state: TerminalShop::Internal::Type::Converter::dump_state
19
20
  ) -> (bool | top)
21
+
22
+ def self.to_sorbet_type: -> top
20
23
  end
21
24
  end
22
25
  end
@@ -23,6 +23,8 @@ module TerminalShop
23
23
  state: TerminalShop::Internal::Type::Converter::dump_state
24
24
  ) -> (Symbol | top)
25
25
 
26
+ def to_sorbet_type: -> top
27
+
26
28
  def inspect: (?depth: Integer) -> String
27
29
  end
28
30
  end
@@ -17,6 +17,8 @@ module TerminalShop
17
17
  Pathname | StringIO | IO | String | top value,
18
18
  state: TerminalShop::Internal::Type::Converter::dump_state
19
19
  ) -> (Pathname | StringIO | IO | String | top)
20
+
21
+ def self.to_sorbet_type: -> top
20
22
  end
21
23
  end
22
24
  end
@@ -3,6 +3,7 @@ module TerminalShop
3
3
  module Type
4
4
  class HashOf[Elem]
5
5
  include TerminalShop::Internal::Type::Converter
6
+ include TerminalShop::Internal::Util::SorbetRuntimeSupport
6
7
 
7
8
  def self.[]: (
8
9
  ::Hash[Symbol, top]
@@ -27,6 +28,8 @@ module TerminalShop
27
28
  state: TerminalShop::Internal::Type::Converter::dump_state
28
29
  ) -> (::Hash[Symbol, top] | top)
29
30
 
31
+ def to_sorbet_type: -> top
32
+
30
33
  def item_type: -> Elem
31
34
 
32
35
  def nilable?: -> bool
@@ -43,6 +43,8 @@ module TerminalShop
43
43
  state: TerminalShop::Internal::Type::Converter::dump_state
44
44
  ) -> top
45
45
 
46
+ def to_sorbet_type: -> top
47
+
46
48
  def inspect: (?depth: Integer) -> String
47
49
  end
48
50
  end
@@ -3,6 +3,7 @@ module TerminalShop
3
3
  module Type
4
4
  class Unknown
5
5
  extend TerminalShop::Internal::Type::Converter
6
+ extend TerminalShop::Internal::Util::SorbetRuntimeSupport
6
7
 
7
8
  def self.===: (top other) -> bool
8
9
 
@@ -17,6 +18,8 @@ module TerminalShop
17
18
  top value,
18
19
  state: TerminalShop::Internal::Type::Converter::dump_state
19
20
  ) -> top
21
+
22
+ def self.to_sorbet_type: -> top
20
23
  end
21
24
  end
22
25
  end
@@ -5,6 +5,10 @@ module TerminalShop
5
5
 
6
6
  def self?.monotonic_secs: -> Float
7
7
 
8
+ def self?.walk_namespaces: (
9
+ Module | Class ns
10
+ ) -> Enumerable[(Module | Class)]
11
+
8
12
  def self?.arch: -> String
9
13
 
10
14
  def self?.os: -> String
@@ -166,7 +170,15 @@ module TerminalShop
166
170
 
167
171
  def const_missing: (Symbol name) -> void
168
172
 
173
+ def sorbet_constant_defined?: (Symbol name) -> bool
174
+
169
175
  def define_sorbet_constant!: (Symbol name) { -> top } -> void
176
+
177
+ def to_sorbet_type: -> top
178
+
179
+ def self.to_sorbet_type: (
180
+ TerminalShop::Internal::Util::SorbetRuntimeSupport | top `type`
181
+ ) -> top
170
182
  end
171
183
  end
172
184
  end
@@ -2,6 +2,8 @@ module TerminalShop
2
2
  module Internal
3
3
  extend TerminalShop::Internal::Util::SorbetRuntimeSupport
4
4
 
5
+ type file_input = Pathname | StringIO | IO | String | TerminalShop::FilePart
6
+
5
7
  OMIT: Object
6
8
  end
7
9
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: terminal-shop
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.0
4
+ version: 3.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Terminal
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-14 00:00:00.000000000 Z
11
+ date: 2025-05-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: connection_pool