seam 2.0.0a2 → 2.0.0b0

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +54 -51
  3. data/README.md +323 -3
  4. data/Rakefile +4 -1
  5. data/lib/seam/auth.rb +118 -0
  6. data/lib/seam/base_resource.rb +63 -0
  7. data/lib/seam/deep_hash_accessor.rb +37 -0
  8. data/lib/seam/default_endpoint.rb +5 -0
  9. data/lib/seam/helpers/action_attempt.rb +45 -0
  10. data/lib/seam/http.rb +52 -0
  11. data/lib/seam/http_multi_workspace.rb +62 -0
  12. data/lib/seam/http_single_workspace.rb +42 -0
  13. data/lib/seam/options.rb +64 -0
  14. data/lib/seam/parse_options.rb +23 -0
  15. data/lib/seam/request.rb +82 -51
  16. data/lib/seam/routes/clients/access_codes.rb +74 -0
  17. data/lib/seam/routes/clients/access_codes_simulate.rb +18 -0
  18. data/lib/seam/routes/clients/access_codes_unmanaged.rb +42 -0
  19. data/lib/seam/routes/clients/acs.rb +44 -0
  20. data/lib/seam/routes/clients/acs_access_groups.rb +48 -0
  21. data/lib/seam/routes/clients/acs_access_groups_unmanaged.rb +24 -0
  22. data/lib/seam/routes/clients/acs_credential_pools.rb +18 -0
  23. data/lib/seam/routes/clients/acs_credential_provisioning_automations.rb +18 -0
  24. data/lib/seam/routes/clients/acs_credentials.rb +60 -0
  25. data/lib/seam/routes/clients/acs_credentials_unmanaged.rb +24 -0
  26. data/lib/seam/routes/clients/acs_encoders.rb +36 -0
  27. data/lib/seam/routes/clients/acs_entrances.rb +36 -0
  28. data/lib/seam/routes/clients/acs_systems.rb +30 -0
  29. data/lib/seam/routes/clients/acs_users.rb +78 -0
  30. data/lib/seam/routes/clients/acs_users_unmanaged.rb +24 -0
  31. data/lib/seam/routes/clients/action_attempts.rb +28 -0
  32. data/lib/seam/routes/clients/client_sessions.rb +54 -0
  33. data/lib/seam/routes/clients/connect_webviews.rb +36 -0
  34. data/lib/seam/routes/clients/connected_accounts.rb +36 -0
  35. data/lib/seam/routes/clients/devices.rb +50 -0
  36. data/lib/seam/routes/clients/devices_simulate.rb +30 -0
  37. data/lib/seam/routes/clients/devices_unmanaged.rb +30 -0
  38. data/lib/seam/routes/clients/events.rb +24 -0
  39. data/lib/seam/routes/clients/index.rb +38 -0
  40. data/lib/seam/routes/clients/locks.rb +42 -0
  41. data/lib/seam/routes/clients/networks.rb +24 -0
  42. data/lib/seam/routes/clients/noise_sensors.rb +26 -0
  43. data/lib/seam/routes/clients/noise_sensors_noise_thresholds.rb +42 -0
  44. data/lib/seam/routes/clients/noise_sensors_simulate.rb +18 -0
  45. data/lib/seam/routes/clients/phones.rb +28 -0
  46. data/lib/seam/routes/clients/phones_simulate.rb +18 -0
  47. data/lib/seam/routes/clients/thermostats.rb +108 -0
  48. data/lib/seam/routes/clients/thermostats_schedules.rb +42 -0
  49. data/lib/seam/routes/clients/user_identities.rb +88 -0
  50. data/lib/seam/routes/clients/user_identities_enrollment_automations.rb +36 -0
  51. data/lib/seam/routes/clients/webhooks.rb +42 -0
  52. data/lib/seam/routes/clients/workspaces.rb +40 -0
  53. data/lib/seam/routes/resources/access_code.rb +14 -0
  54. data/lib/seam/routes/resources/acs_access_group.rb +11 -0
  55. data/lib/seam/routes/resources/acs_credential.rb +14 -0
  56. data/lib/seam/routes/resources/acs_credential_pool.rb +11 -0
  57. data/lib/seam/routes/resources/acs_credential_provisioning_automation.rb +11 -0
  58. data/lib/seam/routes/resources/acs_entrance.rb +13 -0
  59. data/lib/seam/routes/resources/acs_system.rb +14 -0
  60. data/lib/seam/routes/resources/acs_user.rb +14 -0
  61. data/lib/seam/routes/resources/action_attempt.rb +9 -0
  62. data/lib/seam/routes/resources/client_session.rb +11 -0
  63. data/lib/seam/routes/resources/connect_webview.rb +11 -0
  64. data/lib/seam/routes/resources/connected_account.rb +14 -0
  65. data/lib/seam/routes/resources/device.rb +14 -0
  66. data/lib/seam/routes/resources/device_provider.rb +9 -0
  67. data/lib/seam/routes/resources/enrollment_automation.rb +11 -0
  68. data/lib/seam/routes/resources/event.rb +11 -0
  69. data/lib/seam/routes/resources/index.rb +33 -0
  70. data/lib/seam/routes/resources/network.rb +11 -0
  71. data/lib/seam/routes/resources/noise_threshold.rb +9 -0
  72. data/lib/seam/routes/resources/phone.rb +14 -0
  73. data/lib/seam/routes/resources/resource_error.rb +11 -0
  74. data/lib/seam/routes/resources/resource_errors_support.rb +11 -0
  75. data/lib/seam/routes/resources/resource_warning.rb +11 -0
  76. data/lib/seam/routes/resources/resource_warnings_support.rb +11 -0
  77. data/lib/seam/routes/resources/service_health.rb +9 -0
  78. data/lib/seam/routes/resources/thermostat_schedule.rb +13 -0
  79. data/lib/seam/routes/resources/unmanaged_access_code.rb +14 -0
  80. data/lib/seam/routes/resources/unmanaged_device.rb +14 -0
  81. data/lib/seam/routes/resources/user_identity.rb +11 -0
  82. data/lib/seam/routes/resources/webhook.rb +9 -0
  83. data/lib/seam/routes/resources/workspace.rb +9 -0
  84. data/lib/seam/routes/routes.rb +94 -0
  85. data/lib/seam/token.rb +53 -0
  86. data/lib/seam/version.rb +1 -1
  87. data/lib/seam/wait_for_action_attempt.rb +32 -0
  88. data/lib/seam/webhook.rb +22 -0
  89. data/lib/seam.rb +19 -68
  90. metadata +115 -70
  91. data/lib/seam/client.rb +0 -129
  92. data/lib/seam/clients/access_codes.rb +0 -95
  93. data/lib/seam/clients/access_codes_simulate.rb +0 -17
  94. data/lib/seam/clients/access_codes_unmanaged.rb +0 -57
  95. data/lib/seam/clients/acs.rb +0 -35
  96. data/lib/seam/clients/acs_access_groups.rb +0 -57
  97. data/lib/seam/clients/acs_credential_pools.rb +0 -17
  98. data/lib/seam/clients/acs_credential_provisioning_automations.rb +0 -17
  99. data/lib/seam/clients/acs_credentials.rb +0 -77
  100. data/lib/seam/clients/acs_entrances.rb +0 -47
  101. data/lib/seam/clients/acs_systems.rb +0 -27
  102. data/lib/seam/clients/acs_users.rb +0 -117
  103. data/lib/seam/clients/action_attempts.rb +0 -30
  104. data/lib/seam/clients/base_client.rb +0 -21
  105. data/lib/seam/clients/client_sessions.rb +0 -77
  106. data/lib/seam/clients/connect_webviews.rb +0 -47
  107. data/lib/seam/clients/connected_accounts.rb +0 -47
  108. data/lib/seam/clients/devices.rb +0 -65
  109. data/lib/seam/clients/devices_simulate.rb +0 -17
  110. data/lib/seam/clients/devices_unmanaged.rb +0 -37
  111. data/lib/seam/clients/events.rb +0 -27
  112. data/lib/seam/clients/locks.rb +0 -53
  113. data/lib/seam/clients/networks.rb +0 -27
  114. data/lib/seam/clients/noise_sensors.rb +0 -15
  115. data/lib/seam/clients/noise_sensors_noise_thresholds.rb +0 -57
  116. data/lib/seam/clients/noise_sensors_simulate.rb +0 -17
  117. data/lib/seam/clients/phones.rb +0 -31
  118. data/lib/seam/clients/phones_simulate.rb +0 -17
  119. data/lib/seam/clients/thermostats.rb +0 -106
  120. data/lib/seam/clients/thermostats_climate_setting_schedules.rb +0 -57
  121. data/lib/seam/clients/user_identities.rb +0 -131
  122. data/lib/seam/clients/user_identities_enrollment_automations.rb +0 -47
  123. data/lib/seam/clients/webhooks.rb +0 -57
  124. data/lib/seam/clients/workspaces.rb +0 -50
  125. data/lib/seam/resources/access_code.rb +0 -12
  126. data/lib/seam/resources/acs_access_group.rb +0 -9
  127. data/lib/seam/resources/acs_credential.rb +0 -12
  128. data/lib/seam/resources/acs_credential_pool.rb +0 -9
  129. data/lib/seam/resources/acs_credential_provisioning_automation.rb +0 -9
  130. data/lib/seam/resources/acs_entrance.rb +0 -9
  131. data/lib/seam/resources/acs_system.rb +0 -9
  132. data/lib/seam/resources/acs_user.rb +0 -9
  133. data/lib/seam/resources/action_attempt.rb +0 -46
  134. data/lib/seam/resources/base_resource.rb +0 -58
  135. data/lib/seam/resources/client_session.rb +0 -9
  136. data/lib/seam/resources/climate_setting_schedule.rb +0 -11
  137. data/lib/seam/resources/connect_webview.rb +0 -9
  138. data/lib/seam/resources/connected_account.rb +0 -12
  139. data/lib/seam/resources/device.rb +0 -12
  140. data/lib/seam/resources/device_provider.rb +0 -7
  141. data/lib/seam/resources/enrollment_automation.rb +0 -9
  142. data/lib/seam/resources/event.rb +0 -9
  143. data/lib/seam/resources/network.rb +0 -9
  144. data/lib/seam/resources/noise_threshold.rb +0 -7
  145. data/lib/seam/resources/phone.rb +0 -12
  146. data/lib/seam/resources/resource_error.rb +0 -9
  147. data/lib/seam/resources/resource_errors_support.rb +0 -9
  148. data/lib/seam/resources/resource_warning.rb +0 -9
  149. data/lib/seam/resources/resource_warnings_support.rb +0 -9
  150. data/lib/seam/resources/service_health.rb +0 -7
  151. data/lib/seam/resources/unmanaged_access_code.rb +0 -12
  152. data/lib/seam/resources/unmanaged_device.rb +0 -12
  153. data/lib/seam/resources/user_identity.rb +0 -9
  154. data/lib/seam/resources/webhook.rb +0 -7
  155. data/lib/seam/resources/workspace.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3bb7a5a7828d18d2b54017d76ed325d0e7e25c482de942eca0330da40f7e1105
4
- data.tar.gz: 8a86ca467008bb6f8d2b76394f9f773a938f072a384a29dc78dc16e430917bb3
3
+ metadata.gz: f62e294d25f9d5ed9508e9b5d240197d5a92809dbbbb31719722fb6075fecf85
4
+ data.tar.gz: 51621ca4919764d502838e432d7722949ef504e1629bdb224a103d432cfc94ab
5
5
  SHA512:
6
- metadata.gz: 138e121c4bc2482ca27d3a74df486effb52d749de8e1af57fa95ec20600c109e7b2779794e2724fbe8436192ce3a40481e693857ca19b99a320ca96fe4623fe6
7
- data.tar.gz: 4ae84ca5a842777f890f5df0cbff9252fa22d9658f7d03422abcb992a1412e1a272a538019c0f436290bb0064dea0344292690a919a4aa305ec7b3d84e96a30b
6
+ metadata.gz: dc17fcb3c4583ccedf6aed31be275ca76ad721ed2364ac3820580ecd5954f4bb778a85e66eb26a804cc20ede4dd2aad8db1a7206ad5d829f3bfd40de6187e520
7
+ data.tar.gz: 15de1ddba2b3b0d727aca93235634fa2fb60aece82a6238f06474c8795af1f7f8cd3b4f240d1facfe9d6ee0bc665bc91cae4af9ed8903a14da1b81f58c4190c2
data/Gemfile.lock CHANGED
@@ -1,117 +1,120 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- seam (2.0.0a2)
5
- http (~> 5.2)
4
+ seam (2.0.0b0)
5
+ faraday (~> 2.7)
6
+ faraday-retry (~> 2.2)
7
+ svix (~> 1.30)
6
8
 
7
9
  GEM
8
10
  remote: https://rubygems.org/
9
11
  specs:
10
- addressable (2.8.6)
11
- public_suffix (>= 2.0.2, < 6.0)
12
+ addressable (2.8.7)
13
+ public_suffix (>= 2.0.2, < 7.0)
12
14
  ansi (1.5.0)
13
15
  ast (2.4.2)
14
- base64 (0.2.0)
15
- bigdecimal (3.1.7)
16
+ bigdecimal (3.1.8)
16
17
  crack (1.0.0)
17
18
  bigdecimal
18
19
  rexml
19
20
  diff-lcs (1.5.1)
20
- docile (1.4.0)
21
- domain_name (0.6.20240107)
22
- ffi (1.16.3)
23
- ffi-compiler (1.3.2)
24
- ffi (>= 1.15.5)
25
- rake
21
+ docile (1.4.1)
22
+ ethon (0.16.0)
23
+ ffi (>= 1.15.0)
24
+ faraday (2.12.0)
25
+ faraday-net_http (>= 2.0, < 3.4)
26
+ json
27
+ logger
28
+ faraday-net_http (3.3.0)
29
+ net-http
30
+ faraday-retry (2.2.1)
31
+ faraday (~> 2.0)
32
+ ffi (1.17.0)
33
+ ffi (1.17.0-x86_64-linux-gnu)
26
34
  gem-release (2.2.2)
27
- hashdiff (1.1.0)
28
- http (5.2.0)
29
- addressable (~> 2.8)
30
- base64 (~> 0.1)
31
- http-cookie (~> 1.0)
32
- http-form_data (~> 2.2)
33
- llhttp-ffi (~> 0.5.0)
34
- http-cookie (1.0.5)
35
- domain_name (~> 0.5)
36
- http-form_data (2.3.0)
35
+ hashdiff (1.1.1)
37
36
  json (2.7.2)
38
37
  language_server-protocol (3.17.0.3)
39
38
  lint_roller (1.1.0)
40
- llhttp-ffi (0.5.0)
41
- ffi-compiler (~> 1.0)
42
- rake (~> 13.0)
39
+ logger (1.6.1)
43
40
  multi_json (1.15.0)
44
- parallel (1.24.0)
41
+ net-http (0.4.1)
42
+ uri
43
+ parallel (1.26.3)
45
44
  parse_gemspec (1.0.0)
46
45
  parse_gemspec-cli (1.0.0)
47
46
  multi_json
48
47
  parse_gemspec
49
48
  thor
50
- parser (3.3.0.5)
49
+ parser (3.3.5.0)
51
50
  ast (~> 2.4.1)
52
51
  racc
53
- public_suffix (5.0.5)
54
- racc (1.7.3)
52
+ public_suffix (6.0.1)
53
+ racc (1.8.1)
55
54
  rainbow (3.1.1)
56
55
  rake (13.2.1)
57
- regexp_parser (2.9.0)
58
- rexml (3.2.6)
56
+ regexp_parser (2.9.2)
57
+ rexml (3.3.8)
59
58
  rspec (3.13.0)
60
59
  rspec-core (~> 3.13.0)
61
60
  rspec-expectations (~> 3.13.0)
62
61
  rspec-mocks (~> 3.13.0)
63
- rspec-core (3.13.0)
62
+ rspec-core (3.13.2)
64
63
  rspec-support (~> 3.13.0)
65
- rspec-expectations (3.13.0)
64
+ rspec-expectations (3.13.3)
66
65
  diff-lcs (>= 1.2.0, < 2.0)
67
66
  rspec-support (~> 3.13.0)
68
- rspec-mocks (3.13.0)
67
+ rspec-mocks (3.13.2)
69
68
  diff-lcs (>= 1.2.0, < 2.0)
70
69
  rspec-support (~> 3.13.0)
71
70
  rspec-support (3.13.1)
72
- rubocop (1.62.1)
71
+ rubocop (1.66.1)
73
72
  json (~> 2.3)
74
73
  language_server-protocol (>= 3.17.0)
75
74
  parallel (~> 1.10)
76
75
  parser (>= 3.3.0.2)
77
76
  rainbow (>= 2.2.2, < 4.0)
78
- regexp_parser (>= 1.8, < 3.0)
79
- rexml (>= 3.2.5, < 4.0)
80
- rubocop-ast (>= 1.31.1, < 2.0)
77
+ regexp_parser (>= 2.4, < 3.0)
78
+ rubocop-ast (>= 1.32.2, < 2.0)
81
79
  ruby-progressbar (~> 1.7)
82
80
  unicode-display_width (>= 2.4.0, < 3.0)
83
- rubocop-ast (1.31.2)
84
- parser (>= 3.3.0.4)
85
- rubocop-performance (1.20.2)
81
+ rubocop-ast (1.32.3)
82
+ parser (>= 3.3.1.0)
83
+ rubocop-performance (1.22.1)
86
84
  rubocop (>= 1.48.1, < 2.0)
87
- rubocop-ast (>= 1.30.0, < 2.0)
85
+ rubocop-ast (>= 1.31.1, < 2.0)
88
86
  ruby-progressbar (1.13.0)
89
87
  simplecov (0.22.0)
90
88
  docile (~> 1.1)
91
89
  simplecov-html (~> 0.11)
92
90
  simplecov_json_formatter (~> 0.1)
93
- simplecov-console (0.9.1)
91
+ simplecov-console (0.9.2)
94
92
  ansi
95
93
  simplecov
96
94
  terminal-table
97
- simplecov-html (0.12.3)
95
+ simplecov-html (0.13.1)
98
96
  simplecov_json_formatter (0.1.4)
99
- standard (1.35.1)
97
+ standard (1.41.1)
100
98
  language_server-protocol (~> 3.17.0.2)
101
99
  lint_roller (~> 1.0)
102
- rubocop (~> 1.62.0)
100
+ rubocop (~> 1.66.0)
103
101
  standard-custom (~> 1.0.0)
104
- standard-performance (~> 1.3)
102
+ standard-performance (~> 1.5)
105
103
  standard-custom (1.0.2)
106
104
  lint_roller (~> 1.0)
107
105
  rubocop (~> 1.50)
108
- standard-performance (1.3.1)
106
+ standard-performance (1.5.0)
109
107
  lint_roller (~> 1.1)
110
- rubocop-performance (~> 1.20.2)
108
+ rubocop-performance (~> 1.22.0)
109
+ svix (1.38.0)
110
+ typhoeus (~> 1.0, >= 1.0.1)
111
111
  terminal-table (3.0.2)
112
112
  unicode-display_width (>= 1.1.1, < 3)
113
- thor (1.3.1)
114
- unicode-display_width (2.5.0)
113
+ thor (1.3.2)
114
+ typhoeus (1.4.1)
115
+ ethon (>= 0.9.0)
116
+ unicode-display_width (2.6.0)
117
+ uri (0.13.1)
115
118
  webmock (3.0.1)
116
119
  addressable (>= 2.3.6)
117
120
  crack (>= 0.3.2)
data/README.md CHANGED
@@ -7,17 +7,337 @@ SDK for the Seam API written in Ruby.
7
7
 
8
8
  ## Description
9
9
 
10
- TODO
10
+ [Seam](https://seam.co) makes it easy to integrate IoT devices with your applications.
11
+ This is an official SDK for the Seam API.
12
+ Please refer to the official [Seam Docs](https://docs.seam.co/latest/) to get started.
13
+
14
+ Parts of this SDK are generated from always up-to-date type information
15
+ provided by [@seamapi/types](https://github.com/seamapi/types/).
16
+ This ensures all API methods, request shapes, and response shapes are
17
+ accurate and fully typed.
18
+
19
+ <!-- toc -->
20
+
21
+ - [Installation](#installation)
22
+ - [Usage](#usage)
23
+ - [Examples](#examples)
24
+ - [List devices](#list-devices)
25
+ - [Unlock a door](#unlock-a-door)
26
+ - [Authentication Method](#authentication-method)
27
+ - [API Key](#api-key)
28
+ - [Personal Access Token](#personal-access-token)
29
+ - [Action Attempts](#action-attempts)
30
+ - [Interacting with Multiple Workspaces](#interacting-with-multiple-workspaces)
31
+ - [Webhooks](#webhooks)
32
+ - [Advanced Usage](#advanced-usage)
33
+ - [Additional Options](#additional-options)
34
+ - [Setting the endpoint](#setting-the-endpoint)
35
+ - [Configuring the Faraday Client](#configuring-the-faraday-client)
36
+ - [Using the Faraday Client](#using-the-faraday-client)
37
+ - [Overriding the Client](#overriding-the-client)
38
+ - [Development and Testing](#development-and-testing)
39
+ - [Quickstart](#quickstart)
40
+ - [Source code](#source-code)
41
+ - [Requirements](#requirements)
42
+ - [Publishing](#publishing)
43
+ - [Automatic](#automatic)
44
+ - [Manual](#manual)
45
+ - [GitHub Actions](#github-actions)
46
+ - [Secrets for Optional GitHub Actions](#secrets-for-optional-github-actions)
47
+ - [Contributing](#contributing)
48
+ - [License](#license)
49
+ - [Warranty](#warranty)
50
+
51
+ <!-- tocstop -->
11
52
 
12
53
  ## Installation
13
54
 
14
- Add this as a dependency to your project using [Bundler] with
55
+ Add this as a dependency to your project using [Bundler] with:
15
56
 
16
57
  ```
17
58
  $ bundle add seam
18
59
  ```
19
60
 
20
- [bundler]: https://bundler.io/
61
+ [Bundler]: https://bundler.io/
62
+
63
+ ## Usage
64
+
65
+ ### Examples
66
+
67
+ > [!NOTE]
68
+ > These examples assume `SEAM_API_KEY` is set in your environment.
69
+
70
+ #### List devices
71
+
72
+ ```ruby
73
+ require "seam"
74
+
75
+ seam = Seam.new
76
+ devices = seam.devices.list
77
+ ```
78
+
79
+ #### Unlock a door
80
+
81
+ ```ruby
82
+ require "seam"
83
+
84
+ seam = Seam.new
85
+ lock = seam.locks.get(name: "Front Door")
86
+ seam.locks.unlock_door(device_id: lock.device_id)
87
+ ```
88
+
89
+ ### Authentication Method
90
+
91
+ The SDK supports API key and personal access token authentication mechanisms.
92
+ Authentication may be configured by passing the corresponding options directly to the `Seam` constructor, or with the more ergonomic static factory methods.
93
+
94
+ #### API Key
95
+
96
+ An API key is scoped to a single workspace and should only be used on the server.
97
+ Obtain one from the Seam Console.
98
+
99
+ ```ruby
100
+ # Set the `SEAM_API_KEY` environment variable
101
+ seam = Seam.new
102
+
103
+ # Pass as a keyword argument to the constructor
104
+ seam = Seam.new(api_key: "your-api-key")
105
+
106
+ # Use the factory method
107
+ seam = Seam.from_api_key("your-api-key")
108
+ ```
109
+
110
+ #### Personal Access Token
111
+
112
+ A Personal Access Token is scoped to a Seam Console user.
113
+ Obtain one from the Seam Console.
114
+ A workspace ID must be provided when using this method and all requests will be scoped to that workspace.
115
+
116
+ ```ruby
117
+ # Pass as an option to the constructor
118
+ seam = Seam.new(
119
+ personal_access_token: "your-personal-access-token",
120
+ workspace_id: "your-workspace-id"
121
+ )
122
+
123
+ # Use the factory method
124
+ seam = Seam.from_personal_access_token(
125
+ "your-personal-access-token",
126
+ "your-workspace-id"
127
+ )
128
+ ```
129
+
130
+ ### Action Attempts
131
+
132
+ Some asynchronous operations, e.g., unlocking a door, return an
133
+ [action attempt](https://docs.seam.co/latest/core-concepts/action-attempts).
134
+ Seam tracks the progress of the requested operation and updates the action attempt
135
+ when it succeeds or fails.
136
+
137
+ To make working with action attempts more convenient for applications,
138
+ this library provides the `wait_for_action_attempt` option and enables it by default.
139
+
140
+ When the `wait_for_action_attempt` option is enabled, the SDK:
141
+
142
+ - Polls the action attempt up to the `timeout`
143
+ at the `polling_interval` (both in seconds).
144
+ - Resolves with a fresh copy of the successful action attempt.
145
+ - Raises a `Seam::ActionAttemptFailedError` if the action attempt is unsuccessful.
146
+ - Raises a `Seam::ActionAttemptTimeoutError` if the action attempt is still pending when the `timeout` is reached.
147
+ - Both errors expose an `action_attempt` property.
148
+
149
+ If you already have an action attempt ID
150
+ and want to wait for it to resolve, simply use:
151
+
152
+ ```ruby
153
+ seam.action_attempts.get(action_attempt_id: action_attempt_id)
154
+ ```
155
+
156
+ Or, to get the current state of an action attempt by ID without waiting:
157
+
158
+ ```ruby
159
+ seam.action_attempts.get(
160
+ action_attempt_id: action_attempt_id,
161
+ wait_for_action_attempt: false
162
+ )
163
+ ```
164
+
165
+ To disable this behavior, set the default option for the client:
166
+
167
+ ```ruby
168
+ seam = Seam.new(
169
+ api_key: "your-api-key",
170
+ wait_for_action_attempt: false
171
+ )
172
+
173
+ seam.locks.unlock_door(device_id: device_id)
174
+ ```
175
+
176
+ or the behavior may be configured per-request:
177
+
178
+ ```ruby
179
+ seam.locks.unlock_door(
180
+ device_id: device_id,
181
+ wait_for_action_attempt: false
182
+ )
183
+ ```
184
+
185
+ The `polling_interval` and `timeout` may be configured for the client or per-request.
186
+ For example:
187
+
188
+ ```ruby
189
+ require "seam"
190
+
191
+ seam = Seam.new("your-api-key")
192
+
193
+ locks = seam.locks.list
194
+
195
+ if locks.empty?
196
+ raise "No locks in this workspace"
197
+ end
198
+
199
+ lock = locks.first
200
+
201
+ begin
202
+ seam.locks.unlock_door(
203
+ device_id: lock.device_id,
204
+ wait_for_action_attempt: {
205
+ timeout: 5.0,
206
+ polling_interval: 1.0
207
+ }
208
+ )
209
+
210
+ puts "Door unlocked"
211
+ rescue Seam::ActionAttemptFailedError
212
+ puts "Could not unlock the door"
213
+ rescue Seam::ActionAttemptTimeoutError
214
+ puts "Door took too long to unlock"
215
+ end
216
+ ```
217
+
218
+ ### Interacting with Multiple Workspaces
219
+
220
+ 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.
221
+
222
+ A Personal Access Token is scoped to a Seam Console user. Obtain one from the Seam Console.
223
+
224
+ ```ruby
225
+ # Pass as an option to the constructor
226
+ seam = Seam::Http::SeamMultiWorkspace.new(personal_access_token: "your-personal-access-token")
227
+
228
+ # Use the factory method
229
+ seam = Seam::Http::SeamMultiWorkspace.from_personal_access_token("your-personal-access-token")
230
+
231
+ # List workspaces authorized for this Personal Access Token
232
+ workspaces = seam.workspaces.list
233
+ ```
234
+
235
+ ### Webhooks
236
+
237
+ The Seam API implements webhooks using [Svix](https://www.svix.com).This SDK exports a thin wrapper `Seam::Webhook` around the svix package.
238
+ Use it to parse and validate Seam webhook events.
239
+
240
+ > [!TIP]
241
+ > This example is for [Sinatra](https://sinatrarb.com/), see the [Svix docs for more examples in specific frameworks](https://docs.svix.com/receiving/verifying-payloads/how).
242
+
243
+ ```ruby
244
+ require "sinatra"
245
+ require "seam"
246
+
247
+ webhook = Seam::Webhook.new(ENV["SEAM_WEBHOOK_SECRET"])
248
+
249
+ post "/webhook" do
250
+ begin
251
+ headers = {
252
+ "svix-id" => request.env["HTTP_SVIX_ID"],
253
+ "svix-signature" => request.env["HTTP_SVIX_SIGNATURE"],
254
+ "svix-timestamp" => request.env["HTTP_SVIX_TIMESTAMP"]
255
+ }
256
+ data = webhook.verify(request.body.read, headers)
257
+ rescue Seam::WebhookVerificationError
258
+ halt 400, "Bad Request"
259
+ end
260
+
261
+ begin
262
+ store_event(data)
263
+ rescue
264
+ halt 500, "Internal Server Error"
265
+ end
266
+
267
+ 204
268
+ end
269
+
270
+ def store_event(data)
271
+ puts data
272
+ end
273
+ ```
274
+
275
+ ### Advanced Usage
276
+
277
+ #### Additional Options
278
+
279
+ In addition to the various authentication options,
280
+ the constructor takes some advanced options that affect behavior.
281
+
282
+ ```ruby
283
+ seam = Seam.new(
284
+ api_key: "your-api-key",
285
+ endpoint: "https://example.com",
286
+ faraday_options: {},
287
+ faraday_retry_options: {}
288
+ )
289
+ ```
290
+
291
+ When using the static factory methods,
292
+ these options may be passed in as keyword arguments.
293
+
294
+ ```ruby
295
+ seam = Seam.from_api_key("some-api-key",
296
+ endpoint: "https://example.com",
297
+ faraday_options: {},
298
+ faraday_retry_options: {})
299
+ ```
300
+
301
+ #### Setting the endpoint
302
+
303
+ Some contexts may need to override the API endpoint,
304
+ e.g., testing or proxy setups. This option corresponds to the [Faraday](https://lostisland.github.io/faraday/#/) `url` setting.
305
+
306
+ Either pass the `endpoint` option, or set the `SEAM_ENDPOINT` environment variable.
307
+
308
+ #### Configuring the Faraday Client
309
+
310
+ The Faraday client and retry behavior may be configured with custom initiation options
311
+ via [`faraday_option`][faraday_option] and [`faraday_retry_option`][faraday_retry_option].
312
+
313
+ [faraday_option]: https://lostisland.github.io/faraday/#/customization/connection-options?id=connection-options
314
+ [faraday_retry_option]: https://github.com/lostisland/faraday-retry
315
+
316
+ #### Using the Faraday Client
317
+
318
+ The Faraday client is exposed and may be used or configured directly:
319
+
320
+ ```ruby
321
+ require "seam"
322
+ require "faraday"
323
+
324
+ class MyMiddleware < Faraday::Middleware
325
+ def on_complete(env)
326
+ puts env.response.inspect
327
+ end
328
+ end
329
+
330
+ seam = Seam.new
331
+
332
+ seam.client.builder.use MyMiddleware
333
+
334
+ devices = seam.client.get("/devices/list").body["devices"]
335
+ ```
336
+
337
+ #### Overriding the Client
338
+
339
+ A Faraday compatible client may be provided to create a `Seam` instance.
340
+ This API is used internally and is not directly supported.
21
341
 
22
342
  ## Development and Testing
23
343
 
data/Rakefile CHANGED
@@ -5,7 +5,10 @@ require "rspec/core/rake_task"
5
5
  require "standard/rake"
6
6
 
7
7
  RSpec::Core::RakeTask.new(:spec) do |t|
8
- t.rspec_opts = "--pattern spec/**/*_spec.rb"
8
+ t.pattern = [
9
+ "spec/**/*_spec.rb",
10
+ "lib/seam/*_spec.rb"
11
+ ]
9
12
  end
10
13
 
11
14
  task default: %i[lint test]
data/lib/seam/auth.rb ADDED
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "options"
4
+ require_relative "token"
5
+
6
+ module Seam
7
+ module Http
8
+ module Auth
9
+ class SeamInvalidTokenError < StandardError
10
+ def initialize(message)
11
+ super("Seam received an invalid token: #{message}")
12
+ end
13
+ end
14
+
15
+ def self.get_auth_headers(api_key: nil, personal_access_token: nil, workspace_id: nil)
16
+ if Http::Options.seam_http_options_with_api_key?(api_key: api_key, personal_access_token: personal_access_token)
17
+ return get_auth_headers_for_api_key(api_key)
18
+ end
19
+
20
+ if Http::Options.seam_http_options_with_personal_access_token?(personal_access_token: personal_access_token, api_key: api_key,
21
+ workspace_id: workspace_id)
22
+ return get_auth_headers_for_personal_access_token(personal_access_token, workspace_id)
23
+ end
24
+
25
+ raise Http::Options::SeamInvalidOptionsError.new(
26
+ "Must specify an api_key or personal_access_token. " \
27
+ "Attempted reading configuration from the environment, " \
28
+ "but the environment variable SEAM_API_KEY is not set."
29
+ )
30
+ end
31
+
32
+ def self.get_auth_headers_for_api_key(api_key)
33
+ if Auth.client_session_token?(api_key)
34
+ raise SeamInvalidTokenError.new(
35
+ "A Client Session Token cannot be used as an api_key"
36
+ )
37
+ end
38
+
39
+ raise SeamInvalidTokenError.new("A JWT cannot be used as an api_key") if Auth.jwt?(api_key)
40
+
41
+ raise SeamInvalidTokenError.new("An Access Token cannot be used as an api_key") if Auth.access_token?(api_key)
42
+
43
+ if Auth.publishable_key?(api_key)
44
+ raise SeamInvalidTokenError.new(
45
+ "A Publishable Key cannot be used as an api_key"
46
+ )
47
+ end
48
+
49
+ unless Auth.seam_token?(api_key)
50
+ raise SeamInvalidTokenError.new(
51
+ "Unknown or invalid api_key format, expected token to start with #{Auth::TOKEN_PREFIX}"
52
+ )
53
+ end
54
+
55
+ {"authorization" => "Bearer #{api_key}"}
56
+ end
57
+
58
+ def self.get_auth_headers_for_personal_access_token(personal_access_token, workspace_id)
59
+ if Auth.jwt?(personal_access_token)
60
+ raise SeamInvalidTokenError.new(
61
+ "A JWT cannot be used as a personal_access_token"
62
+ )
63
+ end
64
+
65
+ if Auth.client_session_token?(personal_access_token)
66
+ raise SeamInvalidTokenError.new(
67
+ "A Client Session Token cannot be used as a personal_access_token"
68
+ )
69
+ end
70
+
71
+ if Auth.publishable_key?(personal_access_token)
72
+ raise SeamInvalidTokenError.new(
73
+ "A Publishable Key cannot be used as a personal_access_token"
74
+ )
75
+ end
76
+
77
+ unless Auth.access_token?(personal_access_token)
78
+ raise SeamInvalidTokenError.new(
79
+ "Unknown or invalid personal_access_token format, expected token to start with #{Auth::ACCESS_TOKEN_PREFIX}"
80
+ )
81
+ end
82
+
83
+ {
84
+ "authorization" => "Bearer #{personal_access_token}",
85
+ "seam-workspace" => workspace_id
86
+ }
87
+ end
88
+
89
+ def self.get_auth_headers_for_multi_workspace_personal_access_token(personal_access_token)
90
+ if Auth.jwt?(personal_access_token)
91
+ raise SeamInvalidTokenError.new(
92
+ "A JWT cannot be used as a personal_access_token"
93
+ )
94
+ end
95
+
96
+ if Auth.client_session_token?(personal_access_token)
97
+ raise SeamInvalidTokenError.new(
98
+ "A Client Session Token cannot be used as a personal_access_token"
99
+ )
100
+ end
101
+
102
+ if Auth.publishable_key?(personal_access_token)
103
+ raise SeamInvalidTokenError.new(
104
+ "A Publishable Key cannot be used as a personal_access_token"
105
+ )
106
+ end
107
+
108
+ unless Auth.access_token?(personal_access_token)
109
+ raise SeamInvalidTokenError.new(
110
+ "Unknown or invalid personal_access_token format, expected token to start with #{Auth::ACCESS_TOKEN_PREFIX}"
111
+ )
112
+ end
113
+
114
+ {"authorization" => "Bearer #{personal_access_token}"}
115
+ end
116
+ end
117
+ end
118
+ end