seam 2.18.0 → 2.20.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c48c12355ea106daaa28e51b49c82112aa7ad7fd3b763c1c1af67120d307b2bc
4
- data.tar.gz: 312994eaf8ca41fc60d61cf95e8d61cf17b2c24a7471be1eac25ef3fce58545f
3
+ metadata.gz: 6a8ea18ff74b9c148761bee6d9f263d4f724677e515724043dd7eccd4cfe3d3b
4
+ data.tar.gz: a59b64d0e2b47ca9c864a397e077588d2314f0ecec32a7a6fe4214148e72aa76
5
5
  SHA512:
6
- metadata.gz: 36ec7f4184e8a99af08ed91d731c8f505ca682fc62ca46b0440d24b6c43ab3c7dc79f5952559759234bf0a18490c0d8e37c990f60302a5fd3394af8e5c22c678
7
- data.tar.gz: 8ffa2babf798509b894ae45a84d3e83bcd51ec19533043430d0a8b57a4fb27c83d50f4697b9cb7de0ca95ad97abd3e13d95c59c1dbfbb2a3770cba787acd3a1f
6
+ metadata.gz: ee6c631bff63f2df1f4b9978066cb1c9552ce7693d76569f0769c76e4af2ff43fb9c3cbbf055467e4068fe7f5e3d9b0ee48a16d62631b5c709458008164533e7
7
+ data.tar.gz: 3154d05cbedde8d06e6f277a81b47ef325b0bdc996875b665a2fddafd1b94e3cab08b134f6b41f503acc0ef97aa7c078eea78765f416373b11063232046821dc
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- seam (2.18.0)
4
+ seam (2.20.0)
5
5
  faraday (~> 2.7)
6
6
  faraday-retry (~> 2.2)
7
7
  svix (~> 1.30)
data/README.md CHANGED
@@ -27,6 +27,11 @@ accurate and fully typed.
27
27
  - [API Key](#api-key)
28
28
  - [Personal Access Token](#personal-access-token)
29
29
  - [Action Attempts](#action-attempts)
30
+ - [Pagination](#pagination)
31
+ - [Manually fetch pages with the next_page_cursor](#manually-fetch-pages-with-the-next_page_cursor)
32
+ - [Resume pagination](#resume-pagination)
33
+ - [Iterate over all resources](#iterate-over-all-resources)
34
+ - [Return all resources across all pages as a list](#return-all-resources-across-all-pages-as-a-list)
30
35
  - [Interacting with Multiple Workspaces](#interacting-with-multiple-workspaces)
31
36
  - [Webhooks](#webhooks)
32
37
  - [Advanced Usage](#advanced-usage)
@@ -215,6 +220,99 @@ rescue Seam::ActionAttemptTimeoutError
215
220
  end
216
221
  ```
217
222
 
223
+ ### Pagination
224
+
225
+ Some Seam API endpoints that return lists of resources support pagination.
226
+ Use the `Seam::Paginator` class to fetch and process resources across multiple pages.
227
+
228
+ #### Manually fetch pages with the next_page_cursor
229
+
230
+ ```ruby
231
+ require "seam"
232
+
233
+ seam = Seam.new
234
+
235
+ paginator = seam.create_paginator(seam.connected_accounts.method(:list), {limit: 20})
236
+
237
+ connected_accounts, pagination = paginator.first_page
238
+
239
+ if pagination.has_next_page?
240
+ more_connected_accounts, _ = paginator.next_page(pagination.next_page_cursor)
241
+ end
242
+ ```
243
+
244
+ #### Resume pagination
245
+
246
+ Get the first page on initial load and store the state (e.g., in memory or a file):
247
+
248
+ ```ruby
249
+ require "seam"
250
+ require "json"
251
+
252
+ seam = Seam.new
253
+
254
+ params = {limit: 20}
255
+ paginator = seam.create_paginator(seam.connected_accounts.method(:list), params)
256
+
257
+ connected_accounts, pagination = paginator.first_page
258
+
259
+ # Example: Store state for later use (e.g., in a file or database)
260
+ pagination_state = {
261
+ "params" => params,
262
+ "next_page_cursor" => pagination.next_page_cursor,
263
+ "has_next_page" => pagination.has_next_page?
264
+ }
265
+ File.write("/tmp/seam_connected_accounts_list.json", JSON.dump(pagination_state))
266
+ ```
267
+
268
+ Get the next page at a later time using the stored state:
269
+
270
+ ```ruby
271
+ require "seam"
272
+ require "json"
273
+
274
+ seam = Seam.new
275
+
276
+ # Example: Load state from where it was stored
277
+ pagination_state_json = File.read("/tmp/seam_connected_accounts_list.json")
278
+ pagination_state = JSON.parse(pagination_state_json)
279
+
280
+ if pagination_state["has_next_page"]
281
+ paginator = seam.create_paginator(
282
+ seam.connected_accounts.method(:list), pagination_state["params"]
283
+ )
284
+ more_connected_accounts, _ = paginator.next_page(
285
+ pagination_state["next_page_cursor"]
286
+ )
287
+ end
288
+ ```
289
+
290
+ #### Iterate over all resources
291
+
292
+ ```ruby
293
+ require "seam"
294
+
295
+ seam = Seam.new
296
+
297
+ paginator = seam.create_paginator(seam.connected_accounts.method(:list), {limit: 20})
298
+
299
+ paginator.flatten.each do |account|
300
+ puts account.account_type_display_name
301
+ end
302
+ ```
303
+
304
+ #### Return all resources across all pages as a list
305
+
306
+ ```ruby
307
+ require "seam"
308
+
309
+ seam = Seam.new
310
+
311
+ paginator = seam.create_paginator(seam.connected_accounts.method(:list), {limit: 20})
312
+
313
+ all_connected_accounts = paginator.flatten_to_list
314
+ ```
315
+
218
316
  ### Interacting with Multiple Workspaces
219
317
 
220
318
  Some Seam API endpoints interact with multiple workspaces. The `Seam::Http::SeamMultiWorkspace` client is not bound to a specific workspace and may use those endpoints with a personal access token authentication method.
@@ -7,6 +7,7 @@ require_relative "routes/clients/index"
7
7
  require_relative "routes/routes"
8
8
  require_relative "version"
9
9
  require_relative "deep_hash_accessor"
10
+ require_relative "paginator"
10
11
 
11
12
  module Seam
12
13
  module Http
@@ -32,6 +33,10 @@ module Seam
32
33
  Seam::LTS_VERSION
33
34
  end
34
35
 
36
+ def create_paginator(request, params = {})
37
+ Paginator.new(request, params)
38
+ end
39
+
35
40
  def self.from_api_key(api_key, endpoint: nil, wait_for_action_attempt: false, faraday_options: {}, faraday_retry_options: {})
36
41
  new(api_key: api_key, endpoint: endpoint, wait_for_action_attempt: wait_for_action_attempt,
37
42
  faraday_options: faraday_options, faraday_retry_options: faraday_retry_options)
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "faraday"
4
+ require_relative "http"
5
+
6
+ module Seam
7
+ THREAD_CONTEXT_KEY = :seam_pagination_context
8
+ PaginationContext = Struct.new(:pagination)
9
+
10
+ class Paginator
11
+ def initialize(request, params = {})
12
+ raise ArgumentError, "request must be a Method" unless request.is_a?(Method)
13
+ raise ArgumentError, "params must be a Hash" unless params.is_a?(Hash)
14
+
15
+ @request = request
16
+ @params = params.transform_keys(&:to_sym)
17
+ end
18
+
19
+ def first_page
20
+ fetch_page(@params)
21
+ end
22
+
23
+ def next_page(next_page_cursor)
24
+ if next_page_cursor.nil? || next_page_cursor.empty?
25
+ raise ArgumentError,
26
+ "Cannot get the next page with a nil or empty next_page_cursor."
27
+ end
28
+
29
+ fetch_page(@params.merge(page_cursor: next_page_cursor))
30
+ end
31
+
32
+ def flatten_to_list
33
+ all_items = []
34
+ current_items, pagination = first_page
35
+
36
+ all_items.concat(current_items) if current_items
37
+
38
+ while pagination&.has_next_page? && (cursor = pagination.next_page_cursor)
39
+ current_items, pagination = next_page(cursor)
40
+ all_items.concat(current_items) if current_items
41
+ end
42
+
43
+ all_items
44
+ end
45
+
46
+ def flatten
47
+ Enumerator.new do |yielder|
48
+ current_items, pagination = first_page
49
+ current_items&.each { |item| yielder << item }
50
+
51
+ while pagination&.has_next_page? && (cursor = pagination.next_page_cursor)
52
+ current_items, pagination = next_page(cursor)
53
+ current_items&.each { |item| yielder << item }
54
+ end
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def fetch_page(params)
61
+ context = PaginationContext.new(nil)
62
+ Thread.current[THREAD_CONTEXT_KEY] = context
63
+
64
+ begin
65
+ res_data = @request.call(**params)
66
+ pagination_result = Pagination.from_hash(context.pagination)
67
+ [res_data, pagination_result]
68
+ ensure
69
+ Thread.current[THREAD_CONTEXT_KEY] = nil
70
+ end
71
+ end
72
+ end
73
+
74
+ Pagination = Struct.new(:has_next_page, :next_page_cursor, :next_page_url, keyword_init: true) do
75
+ def self.from_hash(hash)
76
+ return nil unless hash.is_a?(Hash) && !hash.empty?
77
+
78
+ new(
79
+ has_next_page: hash.fetch("has_next_page", false),
80
+ next_page_cursor: hash.fetch("next_page_cursor", nil),
81
+ next_page_url: hash.fetch("next_page_url", nil)
82
+ )
83
+ end
84
+
85
+ def has_next_page?
86
+ has_next_page == true
87
+ end
88
+ end
89
+
90
+ class PaginationMiddleware < Faraday::Middleware
91
+ def on_complete(env)
92
+ context = Thread.current[THREAD_CONTEXT_KEY]
93
+ return unless context.is_a?(PaginationContext)
94
+
95
+ pagination_hash = extract_pagination(env)
96
+ context.pagination = pagination_hash if pagination_hash
97
+ end
98
+
99
+ private
100
+
101
+ def extract_pagination(env)
102
+ body = env[:body]
103
+ body["pagination"] if body.is_a?(Hash) && body.key?("pagination")
104
+ end
105
+ end
106
+ end
data/lib/seam/request.rb CHANGED
@@ -4,6 +4,7 @@ require "faraday"
4
4
  require "faraday/retry"
5
5
  require_relative "lts_version"
6
6
  require_relative "version"
7
+ require_relative "paginator"
7
8
 
8
9
  module Seam
9
10
  module Http
@@ -25,6 +26,7 @@ module Seam
25
26
 
26
27
  Faraday.new(options) do |builder|
27
28
  builder.request :json
29
+ builder.use Seam::PaginationMiddleware
28
30
  builder.response :json
29
31
  builder.use ResponseMiddleware
30
32
  builder.request :retry, faraday_retry_options
@@ -30,6 +30,12 @@ module Seam
30
30
  nil
31
31
  end
32
32
 
33
+ def generate_instant_key(user_identity_id:)
34
+ res = @client.post("/user_identities/generate_instant_key", {user_identity_id: user_identity_id}.compact)
35
+
36
+ Seam::Resources::InstantKey.load_from_response(res.body["instant_key"])
37
+ end
38
+
33
39
  def get(user_identity_id: nil, user_identity_key: nil)
34
40
  res = @client.post("/user_identities/get", {user_identity_id: user_identity_id, user_identity_key: user_identity_key}.compact)
35
41
 
@@ -22,6 +22,7 @@ require_relative "device"
22
22
  require_relative "device_provider"
23
23
  require_relative "enrollment_automation"
24
24
  require_relative "event"
25
+ require_relative "instant_key"
25
26
  require_relative "network"
26
27
  require_relative "noise_threshold"
27
28
  require_relative "pagination"
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Seam
4
+ module Resources
5
+ class InstantKey < BaseResource
6
+ attr_accessor :client_session_id, :instant_key_id, :instant_key_url, :user_identity_id, :workspace_id
7
+
8
+ date_accessor :created_at, :expires_at
9
+ end
10
+ end
11
+ end
data/lib/seam/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Seam
4
- VERSION = "2.18.0"
4
+ VERSION = "2.20.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: seam
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.18.0
4
+ version: 2.20.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Seam Labs, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-04-10 00:00:00.000000000 Z
11
+ date: 2025-05-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -200,6 +200,7 @@ files:
200
200
  - lib/seam/http_single_workspace.rb
201
201
  - lib/seam/lts_version.rb
202
202
  - lib/seam/options.rb
203
+ - lib/seam/paginator.rb
203
204
  - lib/seam/parse_options.rb
204
205
  - lib/seam/request.rb
205
206
  - lib/seam/routes/clients/access_codes.rb
@@ -255,6 +256,7 @@ files:
255
256
  - lib/seam/routes/resources/enrollment_automation.rb
256
257
  - lib/seam/routes/resources/event.rb
257
258
  - lib/seam/routes/resources/index.rb
259
+ - lib/seam/routes/resources/instant_key.rb
258
260
  - lib/seam/routes/resources/network.rb
259
261
  - lib/seam/routes/resources/noise_threshold.rb
260
262
  - lib/seam/routes/resources/pagination.rb