seam 2.140.0 → 2.141.1

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +86 -0
  4. data/lib/seam/action_attempt_resolver.rb +54 -0
  5. data/lib/seam/null.rb +23 -0
  6. data/lib/seam/request.rb +49 -1
  7. data/lib/seam/routes/access_codes.rb +1 -1
  8. data/lib/seam/routes/access_codes_unmanaged.rb +1 -1
  9. data/lib/seam/routes/access_grants.rb +6 -6
  10. data/lib/seam/routes/access_grants_unmanaged.rb +1 -1
  11. data/lib/seam/routes/access_methods.rb +5 -5
  12. data/lib/seam/routes/acs_credentials.rb +1 -1
  13. data/lib/seam/routes/acs_encoders.rb +5 -5
  14. data/lib/seam/routes/acs_entrances.rb +4 -4
  15. data/lib/seam/routes/acs_users.rb +2 -2
  16. data/lib/seam/routes/action_attempts.rb +3 -3
  17. data/lib/seam/routes/connect_webviews.rb +1 -1
  18. data/lib/seam/routes/connected_accounts.rb +1 -1
  19. data/lib/seam/routes/devices.rb +3 -3
  20. data/lib/seam/routes/devices_unmanaged.rb +1 -1
  21. data/lib/seam/routes/locks.rb +4 -4
  22. data/lib/seam/routes/locks_simulate.rb +3 -3
  23. data/lib/seam/routes/spaces.rb +1 -1
  24. data/lib/seam/routes/thermostats.rb +22 -22
  25. data/lib/seam/routes/thermostats_daily_programs.rb +2 -2
  26. data/lib/seam/routes/thermostats_schedules.rb +2 -2
  27. data/lib/seam/routes/user_identities.rb +9 -9
  28. data/lib/seam/routes/user_identities_unmanaged.rb +1 -1
  29. data/lib/seam/routes/workspaces.rb +3 -3
  30. data/lib/seam/strict_url_search_params_serializer.rb +17 -0
  31. data/lib/seam/url_search_params.rb +102 -0
  32. data/lib/seam/url_search_params_serializer.rb +217 -0
  33. data/lib/seam/version.rb +1 -1
  34. data/lib/seam.rb +3 -0
  35. metadata +6 -2
  36. data/lib/seam/helpers/action_attempt.rb +0 -56
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "seam/helpers/action_attempt"
3
+ require "seam/action_attempt_resolver"
4
4
 
5
5
  module Seam
6
6
  module Clients
@@ -19,7 +19,7 @@ module Seam
19
19
 
20
20
  wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt
21
21
 
22
- Helpers::ActionAttempt.decide_and_wait(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
22
+ Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
23
23
  end
24
24
 
25
25
  # Simulates a manual lock action using a keypad. You can only perform this action for [August](https://docs.seam.co/device-and-system-integration-guides/august-locks) devices within [sandbox workspaces](https://docs.seam.co/core-concepts/workspaces#sandbox-workspaces).
@@ -30,7 +30,7 @@ module Seam
30
30
 
31
31
  wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt
32
32
 
33
- Helpers::ActionAttempt.decide_and_wait(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
33
+ Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
34
34
  end
35
35
  end
36
36
  end
@@ -95,7 +95,7 @@ module Seam
95
95
  # Returns a list of all spaces.
96
96
  # @param customer_key [String, nil] Customer key for which you want to list spaces.
97
97
  # @param limit [Float, nil] Maximum number of records to return per page.
98
- # @param page_cursor [String, nil] Identifies the specific page of results to return, obtained from the previous page's `next_page_cursor`.
98
+ # @param page_cursor [String, Seam::Null, nil] Identifies the specific page of results to return, obtained from the previous page's `next_page_cursor`.
99
99
  # @param search [String, nil] String for which to search. Filters returned spaces to include all records that satisfy a partial match using `name`, `space_key`, or `customer_key`.
100
100
  # @param space_key [String, nil] Filter spaces by space_key.
101
101
  # @return [Seam::Resources::Space] OK
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "seam/helpers/action_attempt"
3
+ require "seam/action_attempt_resolver"
4
4
 
5
5
  module Seam
6
6
  module Clients
@@ -31,7 +31,7 @@ module Seam
31
31
 
32
32
  wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt
33
33
 
34
- Helpers::ActionAttempt.decide_and_wait(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
34
+ Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
35
35
  end
36
36
 
37
37
  # Sets a specified [thermostat](https://docs.seam.co/capability-guides/thermostats) to [cool mode](https://docs.seam.co/capability-guides/thermostats/configure-current-climate-settings).
@@ -44,7 +44,7 @@ module Seam
44
44
 
45
45
  wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt
46
46
 
47
- Helpers::ActionAttempt.decide_and_wait(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
47
+ Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
48
48
  end
49
49
 
50
50
  # Creates a [climate preset](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-climate-presets) for a specified [thermostat](https://docs.seam.co/capability-guides/thermostats).
@@ -60,7 +60,7 @@ module Seam
60
60
  # @param hvac_mode_setting [String, nil] Desired [HVAC mode](https://docs.seam.co/capability-guides/thermostats/understanding-thermostat-concepts/hvac-mode) setting, such as `heat`, `cool`, `heat_cool`, or `off`.
61
61
  # @param manual_override_allowed [Boolean, nil] Indicates whether a person at the thermostat or using the API can change the thermostat's settings.
62
62
  # @deprecated manual_override_allowed: Use 'thermostat_schedule.is_override_allowed'
63
- # @param name [String, nil] User-friendly name to identify the [climate preset](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-climate-presets).
63
+ # @param name [String, Seam::Null, nil] User-friendly name to identify the [climate preset](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-climate-presets).
64
64
  # @return [nil] OK
65
65
  def create_climate_preset(climate_preset_key:, device_id:, climate_preset_mode: nil, cooling_set_point_celsius: nil, cooling_set_point_fahrenheit: nil, ecobee_metadata: nil, fan_mode_setting: nil, heating_set_point_celsius: nil, heating_set_point_fahrenheit: nil, hvac_mode_setting: nil, manual_override_allowed: nil, name: nil)
66
66
  @client.post("/thermostats/create_climate_preset", {climate_preset_key: climate_preset_key, device_id: device_id, climate_preset_mode: climate_preset_mode, cooling_set_point_celsius: cooling_set_point_celsius, cooling_set_point_fahrenheit: cooling_set_point_fahrenheit, ecobee_metadata: ecobee_metadata, fan_mode_setting: fan_mode_setting, heating_set_point_celsius: heating_set_point_celsius, heating_set_point_fahrenheit: heating_set_point_fahrenheit, hvac_mode_setting: hvac_mode_setting, manual_override_allowed: manual_override_allowed, name: name}.compact)
@@ -88,7 +88,7 @@ module Seam
88
88
 
89
89
  wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt
90
90
 
91
- Helpers::ActionAttempt.decide_and_wait(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
91
+ Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
92
92
  end
93
93
 
94
94
  # Sets a specified [thermostat](https://docs.seam.co/capability-guides/thermostats) to [heat-cool ("auto") mode](https://docs.seam.co/capability-guides/thermostats/configure-current-climate-settings).
@@ -103,7 +103,7 @@ module Seam
103
103
 
104
104
  wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt
105
105
 
106
- Helpers::ActionAttempt.decide_and_wait(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
106
+ Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
107
107
  end
108
108
 
109
109
  # Returns a list of all [thermostats](https://docs.seam.co/capability-guides/thermostats).
@@ -128,7 +128,7 @@ module Seam
128
128
 
129
129
  wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt
130
130
 
131
- Helpers::ActionAttempt.decide_and_wait(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
131
+ Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
132
132
  end
133
133
 
134
134
  # Sets a specified [climate preset](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-climate-presets) as the ["fallback"](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-climate-presets/setting-the-fallback-climate-preset) preset for a specified [thermostat](https://docs.seam.co/capability-guides/thermostats).
@@ -152,7 +152,7 @@ module Seam
152
152
 
153
153
  wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt
154
154
 
155
- Helpers::ActionAttempt.decide_and_wait(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
155
+ Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
156
156
  end
157
157
 
158
158
  # Sets the [HVAC mode](https://docs.seam.co/capability-guides/thermostats/configure-current-climate-settings) for a specified [thermostat](https://docs.seam.co/capability-guides/thermostats).
@@ -168,15 +168,15 @@ module Seam
168
168
 
169
169
  wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt
170
170
 
171
- Helpers::ActionAttempt.decide_and_wait(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
171
+ Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
172
172
  end
173
173
 
174
174
  # Sets a [temperature threshold](https://docs.seam.co/capability-guides/thermostats/setting-and-monitoring-temperature-thresholds) for a specified thermostat. Seam emits a `thermostat.temperature_threshold_exceeded` event and adds a warning on a thermostat if it reports a temperature outside the threshold range.
175
175
  # @param device_id [String] ID of the thermostat device for which you want to set a temperature threshold.
176
- # @param lower_limit_celsius [Float, nil] Lower temperature limit in in °C. Seam alerts you if the reported temperature is lower than this value. You can specify either `lower_limit` but not both.
177
- # @param lower_limit_fahrenheit [Float, nil] Lower temperature limit in in °F. Seam alerts you if the reported temperature is lower than this value. You can specify either `lower_limit` but not both.
178
- # @param upper_limit_celsius [Float, nil] Upper temperature limit in in °C. Seam alerts you if the reported temperature is higher than this value. You can specify either `upper_limit` but not both.
179
- # @param upper_limit_fahrenheit [Float, nil] Upper temperature limit in in °C. Seam alerts you if the reported temperature is higher than this value. You can specify either `upper_limit` but not both.
176
+ # @param lower_limit_celsius [Float, Seam::Null, nil] Lower temperature limit in in °C. Seam alerts you if the reported temperature is lower than this value. You can specify either `lower_limit` but not both.
177
+ # @param lower_limit_fahrenheit [Float, Seam::Null, nil] Lower temperature limit in in °F. Seam alerts you if the reported temperature is lower than this value. You can specify either `lower_limit` but not both.
178
+ # @param upper_limit_celsius [Float, Seam::Null, nil] Upper temperature limit in in °C. Seam alerts you if the reported temperature is higher than this value. You can specify either `upper_limit` but not both.
179
+ # @param upper_limit_fahrenheit [Float, Seam::Null, nil] Upper temperature limit in in °C. Seam alerts you if the reported temperature is higher than this value. You can specify either `upper_limit` but not both.
180
180
  # @return [nil] OK
181
181
  def set_temperature_threshold(device_id:, lower_limit_celsius: nil, lower_limit_fahrenheit: nil, upper_limit_celsius: nil, upper_limit_fahrenheit: nil)
182
182
  @client.patch("/thermostats/set_temperature_threshold", {device_id: device_id, lower_limit_celsius: lower_limit_celsius, lower_limit_fahrenheit: lower_limit_fahrenheit, upper_limit_celsius: upper_limit_celsius, upper_limit_fahrenheit: upper_limit_fahrenheit}.compact)
@@ -197,7 +197,7 @@ module Seam
197
197
  # @param hvac_mode_setting [String, nil] Desired [HVAC mode](https://docs.seam.co/capability-guides/thermostats/understanding-thermostat-concepts/hvac-mode) setting, such as `heat`, `cool`, `heat_cool`, or `off`.
198
198
  # @param manual_override_allowed [Boolean, nil] Indicates whether a person at the thermostat can change the thermostat's settings. See [Specifying Manual Override Permissions](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-thermostat-schedules#specifying-manual-override-permissions).
199
199
  # @deprecated manual_override_allowed: Use 'thermostat_schedule.is_override_allowed'
200
- # @param name [String, nil] User-friendly name to identify the [climate preset](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-climate-presets).
200
+ # @param name [String, Seam::Null, nil] User-friendly name to identify the [climate preset](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-climate-presets).
201
201
  # @return [nil] OK
202
202
  def update_climate_preset(climate_preset_key:, device_id:, climate_preset_mode: nil, cooling_set_point_celsius: nil, cooling_set_point_fahrenheit: nil, ecobee_metadata: nil, fan_mode_setting: nil, heating_set_point_celsius: nil, heating_set_point_fahrenheit: nil, hvac_mode_setting: nil, manual_override_allowed: nil, name: nil)
203
203
  @client.patch("/thermostats/update_climate_preset", {climate_preset_key: climate_preset_key, device_id: device_id, climate_preset_mode: climate_preset_mode, cooling_set_point_celsius: cooling_set_point_celsius, cooling_set_point_fahrenheit: cooling_set_point_fahrenheit, ecobee_metadata: ecobee_metadata, fan_mode_setting: fan_mode_setting, heating_set_point_celsius: heating_set_point_celsius, heating_set_point_fahrenheit: heating_set_point_fahrenheit, hvac_mode_setting: hvac_mode_setting, manual_override_allowed: manual_override_allowed, name: name}.compact)
@@ -207,20 +207,20 @@ module Seam
207
207
 
208
208
  # Updates the thermostat weekly program for a thermostat device. To configure a weekly program, specify the ID of the daily program that you want to use for each day of the week. When you update a weekly program, the set of programs that you specify overwrites any previous weekly program for the thermostat.
209
209
  # @param device_id [String] ID of the thermostat device for which you want to update the weekly program.
210
- # @param friday_program_id [String, nil] ID of the thermostat daily program to run on Fridays.
211
- # @param monday_program_id [String, nil] ID of the thermostat daily program to run on Mondays.
212
- # @param saturday_program_id [String, nil] ID of the thermostat daily program to run on Saturdays.
213
- # @param sunday_program_id [String, nil] ID of the thermostat daily program to run on Sundays.
214
- # @param thursday_program_id [String, nil] ID of the thermostat daily program to run on Thursdays.
215
- # @param tuesday_program_id [String, nil] ID of the thermostat daily program to run on Tuesdays.
216
- # @param wednesday_program_id [String, nil] ID of the thermostat daily program to run on Wednesdays.
210
+ # @param friday_program_id [String, Seam::Null, nil] ID of the thermostat daily program to run on Fridays.
211
+ # @param monday_program_id [String, Seam::Null, nil] ID of the thermostat daily program to run on Mondays.
212
+ # @param saturday_program_id [String, Seam::Null, nil] ID of the thermostat daily program to run on Saturdays.
213
+ # @param sunday_program_id [String, Seam::Null, nil] ID of the thermostat daily program to run on Sundays.
214
+ # @param thursday_program_id [String, Seam::Null, nil] ID of the thermostat daily program to run on Thursdays.
215
+ # @param tuesday_program_id [String, Seam::Null, nil] ID of the thermostat daily program to run on Tuesdays.
216
+ # @param wednesday_program_id [String, Seam::Null, nil] ID of the thermostat daily program to run on Wednesdays.
217
217
  # @return [Seam::Resources::ActionAttempt] OK
218
218
  def update_weekly_program(device_id:, friday_program_id: nil, monday_program_id: nil, saturday_program_id: nil, sunday_program_id: nil, thursday_program_id: nil, tuesday_program_id: nil, wednesday_program_id: nil, wait_for_action_attempt: nil)
219
219
  res = @client.post("/thermostats/update_weekly_program", {device_id: device_id, friday_program_id: friday_program_id, monday_program_id: monday_program_id, saturday_program_id: saturday_program_id, sunday_program_id: sunday_program_id, thursday_program_id: thursday_program_id, tuesday_program_id: tuesday_program_id, wednesday_program_id: wednesday_program_id}.compact)
220
220
 
221
221
  wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt
222
222
 
223
- Helpers::ActionAttempt.decide_and_wait(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
223
+ Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
224
224
  end
225
225
  end
226
226
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "seam/helpers/action_attempt"
3
+ require "seam/action_attempt_resolver"
4
4
 
5
5
  module Seam
6
6
  module Clients
@@ -40,7 +40,7 @@ module Seam
40
40
 
41
41
  wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt
42
42
 
43
- Helpers::ActionAttempt.decide_and_wait(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
43
+ Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
44
44
  end
45
45
  end
46
46
  end
@@ -14,7 +14,7 @@ module Seam
14
14
  # @param ends_at [String] Date and time at which the new thermostat schedule ends, in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format.
15
15
  # @param starts_at [String] Date and time at which the new thermostat schedule starts, in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format.
16
16
  # @param is_override_allowed [Boolean, nil] Indicates whether a person at the thermostat or using the API can change the thermostat's settings while the new schedule is active. See also [Specifying Manual Override Permissions](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-thermostat-schedules#specifying-manual-override-permissions).
17
- # @param max_override_period_minutes [Integer, nil] Number of minutes for which a person at the thermostat or using the API can change the thermostat's settings after the activation of the scheduled climate preset. See also [Specifying Manual Override Permissions](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-thermostat-schedules#specifying-manual-override-permissions).
17
+ # @param max_override_period_minutes [Integer, Seam::Null, nil] Number of minutes for which a person at the thermostat or using the API can change the thermostat's settings after the activation of the scheduled climate preset. See also [Specifying Manual Override Permissions](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-thermostat-schedules#specifying-manual-override-permissions).
18
18
  # @param name [String, nil] Name of the thermostat schedule.
19
19
  # @return [Seam::Resources::ThermostatSchedule] OK
20
20
  def create(climate_preset_key:, device_id:, ends_at:, starts_at:, is_override_allowed: nil, max_override_period_minutes: nil, name: nil)
@@ -56,7 +56,7 @@ module Seam
56
56
  # @param climate_preset_key [String, nil] Key of the [climate preset](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-climate-presets) to use for the thermostat schedule.
57
57
  # @param ends_at [String, nil] Date and time at which the thermostat schedule ends, in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format.
58
58
  # @param is_override_allowed [Boolean, nil] Indicates whether a person at the thermostat or using the API can change the thermostat's settings while the schedule is active. See also [Specifying Manual Override Permissions](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-thermostat-schedules#specifying-manual-override-permissions).
59
- # @param max_override_period_minutes [Integer, nil] Number of minutes for which a person at the thermostat or using the API can change the thermostat's settings after the activation of the scheduled climate preset. See also [Specifying Manual Override Permissions](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-thermostat-schedules#specifying-manual-override-permissions).
59
+ # @param max_override_period_minutes [Integer, Seam::Null, nil] Number of minutes for which a person at the thermostat or using the API can change the thermostat's settings after the activation of the scheduled climate preset. See also [Specifying Manual Override Permissions](https://docs.seam.co/capability-guides/thermostats/creating-and-managing-thermostat-schedules#specifying-manual-override-permissions).
60
60
  # @param name [String, nil] Name of the thermostat schedule.
61
61
  # @param starts_at [String, nil] Date and time at which the thermostat schedule starts, in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format.
62
62
  # @return [nil] OK
@@ -29,10 +29,10 @@ module Seam
29
29
 
30
30
  # Creates a new [user identity](https://docs.seam.co/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity).
31
31
  # @param acs_system_ids [Array<String>, nil] List of access system IDs to associate with the new user identity through access system users. If there's no user with the same email address or phone number in the specified access systems, a new access system user is created. If there is an existing user with the same email or phone number in the specified access systems, the user is linked to the user identity.
32
- # @param email_address [String, nil] Unique email address for the new user identity.
33
- # @param full_name [String, nil] Full name of the user associated with the new user identity.
34
- # @param phone_number [String, nil] Unique phone number for the new user identity in E.164 format (for example, +15555550100).
35
- # @param user_identity_key [String, nil] Unique key for the new user identity.
32
+ # @param email_address [String, Seam::Null, nil] Unique email address for the new user identity.
33
+ # @param full_name [String, Seam::Null, nil] Full name of the user associated with the new user identity.
34
+ # @param phone_number [String, Seam::Null, nil] Unique phone number for the new user identity in E.164 format (for example, +15555550100).
35
+ # @param user_identity_key [String, Seam::Null, nil] Unique key for the new user identity.
36
36
  # @return [Seam::Resources::UserIdentity] OK
37
37
  def create(acs_system_ids: nil, email_address: nil, full_name: nil, phone_number: nil, user_identity_key: nil)
38
38
  res = @client.post("/user_identities/create", {acs_system_ids: acs_system_ids, email_address: email_address, full_name: full_name, phone_number: phone_number, user_identity_key: user_identity_key}.compact)
@@ -88,7 +88,7 @@ module Seam
88
88
  # @param created_before [Time, nil] Timestamp by which to limit returned user identities. Returns user identities created before this timestamp.
89
89
  # @param credential_manager_acs_system_id [String, nil] `acs_system_id` of the credential manager by which you want to filter the list of user identities.
90
90
  # @param limit [Integer, nil] Maximum number of records to return per page.
91
- # @param page_cursor [String, nil] Identifies the specific page of results to return, obtained from the previous page's `next_page_cursor`.
91
+ # @param page_cursor [String, Seam::Null, nil] Identifies the specific page of results to return, obtained from the previous page's `next_page_cursor`.
92
92
  # @param search [String, nil] String for which to search. Filters returned user identities to include all records that satisfy a partial match using `full_name`, `phone_number`, `email_address` or `user_identity_id`.
93
93
  # @param user_identity_ids [Array<String>, nil] Array of user identity IDs by which to filter the list of user identities.
94
94
  # @return [Seam::Resources::UserIdentity] OK
@@ -156,10 +156,10 @@ module Seam
156
156
 
157
157
  # Updates a specified [user identity](https://docs.seam.co/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity).
158
158
  # @param user_identity_id [String] ID of the user identity that you want to update.
159
- # @param email_address [String, nil] Unique email address for the user identity.
160
- # @param full_name [String, nil] Full name of the user associated with the user identity.
161
- # @param phone_number [String, nil] Unique phone number for the user identity.
162
- # @param user_identity_key [String, nil] Unique key for the user identity.
159
+ # @param email_address [String, Seam::Null, nil] Unique email address for the user identity.
160
+ # @param full_name [String, Seam::Null, nil] Full name of the user associated with the user identity.
161
+ # @param phone_number [String, Seam::Null, nil] Unique phone number for the user identity.
162
+ # @param user_identity_key [String, Seam::Null, nil] Unique key for the user identity.
163
163
  # @return [nil] OK
164
164
  def update(user_identity_id:, email_address: nil, full_name: nil, phone_number: nil, user_identity_key: nil)
165
165
  @client.patch("/user_identities/update", {user_identity_id: user_identity_id, email_address: email_address, full_name: full_name, phone_number: phone_number, user_identity_key: user_identity_key}.compact)
@@ -20,7 +20,7 @@ module Seam
20
20
  # Returns a list of all unmanaged [user identities](https://docs.seam.co/capability-guides/mobile-access/managing-mobile-app-user-accounts-with-user-identities#what-is-a-user-identity) (where is_managed = false).
21
21
  # @param created_before [Time, nil] Timestamp by which to limit returned unmanaged user identities. Returns user identities created before this timestamp.
22
22
  # @param limit [Integer, nil] Maximum number of records to return per page.
23
- # @param page_cursor [String, nil] Identifies the specific page of results to return, obtained from the previous page's `next_page_cursor`.
23
+ # @param page_cursor [String, Seam::Null, nil] Identifies the specific page of results to return, obtained from the previous page's `next_page_cursor`.
24
24
  # @param search [String, nil] String for which to search. Filters returned unmanaged user identities to include all records that satisfy a partial match using `full_name`, `phone_number`, `email_address`, `user_identity_id` or `acs_system_id`.
25
25
  # @return [Seam::Resources::UnmanagedUserIdentity] OK
26
26
  def list(created_before: nil, limit: nil, page_cursor: nil, search: nil)
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "seam/helpers/action_attempt"
3
+ require "seam/action_attempt_resolver"
4
4
 
5
5
  module Seam
6
6
  module Clients
@@ -13,7 +13,7 @@ module Seam
13
13
  # Creates a new [workspace](https://docs.seam.co/core-concepts/workspaces).
14
14
  # @param name [String] Name of the new workspace.
15
15
  # @param company_name [String, nil] Company name for the new workspace.
16
- # @param connect_partner_name [String, nil] Connect partner name for the new workspace.
16
+ # @param connect_partner_name [String, Seam::Null, nil] Connect partner name for the new workspace.
17
17
  # @deprecated connect_partner_name: Use `company_name` instead.
18
18
  # @param connect_webview_customization [Hash, nil] [Connect Webview](https://docs.seam.co/core-concepts/connect-webviews) customizations for the new workspace. See also [Customize the Look and Feel of Your Connect Webviews](https://docs.seam.co/core-concepts/connect-webviews/customizing-connect-webviews#customize-the-look-and-feel-of-your-connect-webviews).
19
19
  # @param is_sandbox [Boolean, nil] Indicates whether the new workspace is a [sandbox workspace](https://docs.seam.co/core-concepts/workspaces#sandbox-workspaces).
@@ -56,7 +56,7 @@ module Seam
56
56
 
57
57
  wait_for_action_attempt = wait_for_action_attempt.nil? ? @defaults.wait_for_action_attempt : wait_for_action_attempt
58
58
 
59
- Helpers::ActionAttempt.decide_and_wait(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
59
+ Seam::ActionAttemptResolver.resolve(Seam::Resources::ActionAttempt.load_from_response(res.body["action_attempt"]), @client, wait_for_action_attempt)
60
60
  end
61
61
 
62
62
  # Updates the [workspace](https://docs.seam.co/core-concepts/workspaces) associated with the authentication value.
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "url_search_params_serializer"
4
+
5
+ # Strict serialization, used by the SDK itself: _strict=true is added to any
6
+ # non-empty query so the Seam API uses strict, schema-aware parsing.
7
+ module Seam
8
+ # (see UrlSearchParamsSerializer.serialize_url_search_params)
9
+ def self.serialize_url_search_params(params)
10
+ UrlSearchParamsSerializer.serialize_url_search_params(params, strict: true)
11
+ end
12
+
13
+ # (see UrlSearchParamsSerializer.update_url_search_params)
14
+ def self.update_url_search_params(search_params, params)
15
+ UrlSearchParamsSerializer.update_url_search_params(search_params, params, strict: true)
16
+ end
17
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+
5
+ module Seam
6
+ # A mutable, ordered list of name/value string pairs modeling the parts of
7
+ # the WHATWG URLSearchParams interface that the Seam URL search params
8
+ # serializer needs.
9
+ class UrlSearchParams
10
+ include Enumerable
11
+
12
+ # @param init [String, Hash, Enumerable, nil]
13
+ def initialize(init = nil)
14
+ @pairs = []
15
+ return if init.nil?
16
+
17
+ case init
18
+ when String
19
+ query = init.delete_prefix("?")
20
+ URI.decode_www_form(query).each { |name, value| append(name, value) } unless query.empty?
21
+ when Hash
22
+ init.each { |name, value| append(name, value) }
23
+ else
24
+ init.each { |name, value| append(name, value) }
25
+ end
26
+ end
27
+
28
+ def append(name, value)
29
+ @pairs << [name.to_s, value.to_s]
30
+ nil
31
+ end
32
+
33
+ def set(name, value)
34
+ name = name.to_s
35
+ replaced = false
36
+ @pairs = @pairs.filter_map do |pair|
37
+ next pair unless pair.first == name
38
+ next nil if replaced
39
+
40
+ replaced = true
41
+ [name, value.to_s]
42
+ end
43
+ append(name, value) unless replaced
44
+ nil
45
+ end
46
+
47
+ def get(name)
48
+ name = name.to_s
49
+ @pairs.each { |pair_name, value| return value if pair_name == name }
50
+ nil
51
+ end
52
+
53
+ def get_all(name)
54
+ name = name.to_s
55
+ @pairs.filter_map { |pair_name, value| value if pair_name == name }
56
+ end
57
+
58
+ def has?(name)
59
+ name = name.to_s
60
+ @pairs.any? { |pair_name, _| pair_name == name }
61
+ end
62
+
63
+ def delete(name)
64
+ name = name.to_s
65
+ @pairs.reject! { |pair_name, _| pair_name == name }
66
+ nil
67
+ end
68
+
69
+ def sort!
70
+ @pairs = @pairs.each_with_index.sort_by do |(name, _), index|
71
+ [name.encode(Encoding::UTF_16BE).b, index]
72
+ end.map(&:first)
73
+ nil
74
+ end
75
+
76
+ def each(&block)
77
+ return @pairs.each unless block
78
+
79
+ @pairs.each(&block)
80
+ self
81
+ end
82
+
83
+ def size
84
+ @pairs.size
85
+ end
86
+ alias_method :length, :size
87
+
88
+ def empty?
89
+ @pairs.empty?
90
+ end
91
+
92
+ def to_s
93
+ @pairs.map do |name, value|
94
+ "#{self.class.encode_component(name)}=#{self.class.encode_component(value)}"
95
+ end.join("&")
96
+ end
97
+
98
+ def self.encode_component(string)
99
+ URI.encode_www_form_component(string.encode(Encoding::UTF_8))
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,217 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+
5
+ require_relative "null"
6
+ require_relative "url_search_params"
7
+
8
+ module Seam
9
+ class UnserializableParamError < StandardError
10
+ attr_reader :param_name
11
+
12
+ def initialize(param_name, reason)
13
+ @param_name = param_name
14
+ super("Could not serialize parameter: '#{param_name}' #{reason}")
15
+ end
16
+ end
17
+
18
+ def self.replace_null(value)
19
+ case value
20
+ when Seam::Null then nil
21
+ when Hash then value.transform_values { |v| replace_null(v) }
22
+ when Array then value.map { |v| replace_null(v) }
23
+ else value
24
+ end
25
+ end
26
+
27
+ # Serializes parameters to a URL query string following the
28
+ # @seamapi/url-search-params-serializer standard:
29
+ # https://github.com/seamapi/url-search-params-serializer
30
+ module UrlSearchParamsSerializer
31
+ # @param params [Hash]
32
+ # @param strict [Boolean] Whether to add +_strict=true+ to a non-empty
33
+ # query string
34
+ # @return [String] The query string, without a leading +?+
35
+ # @raise [UnserializableParamError]
36
+ def self.serialize_url_search_params(params, strict: false)
37
+ search_params = UrlSearchParams.new
38
+ update_url_search_params(search_params, params, strict: strict)
39
+ search_params.to_s
40
+ end
41
+
42
+ # Serializes parameters into an existing {UrlSearchParams} collection,
43
+ # preserving pairs it does not overwrite.
44
+ #
45
+ # @param search_params [UrlSearchParams]
46
+ # @param params [Hash]
47
+ # @param strict [Boolean] Whether to add +_strict=true+ when the
48
+ # resulting collection is non-empty
49
+ # @return [nil]
50
+ # @raise [UnserializableParamError]
51
+ def self.update_url_search_params(search_params, params, strict: false)
52
+ nested_update(search_params, params, [])
53
+ search_params.sort!
54
+
55
+ if strict && !search_params.empty?
56
+ search_params.delete("_strict")
57
+ search_params.append("_strict", "true")
58
+ end
59
+
60
+ nil
61
+ end
62
+
63
+ def self.nested_update(search_params, params, path)
64
+ params.each do |key, value|
65
+ unless key.is_a?(String) || key.is_a?(Symbol)
66
+ raise UnserializableParamError.new(
67
+ key.inspect,
68
+ "has a name that is not a string which is unsupported"
69
+ )
70
+ end
71
+ key = key.to_s
72
+
73
+ if key.include?(".")
74
+ raise UnserializableParamError.new(
75
+ key,
76
+ 'contains one or more dots "." in its name which is unsupported'
77
+ )
78
+ end
79
+
80
+ current_path = [*path, key]
81
+
82
+ if value.is_a?(Hash)
83
+ nested_update(search_params, value, current_path)
84
+ next
85
+ end
86
+
87
+ name = current_path.join(".")
88
+
89
+ next if value.nil?
90
+
91
+ value = value.to_s if value.is_a?(Symbol)
92
+
93
+ next if value.is_a?(String) && value.empty?
94
+
95
+ if value.is_a?(Array)
96
+ serialize_array(search_params, name, value)
97
+ next
98
+ end
99
+
100
+ search_params.set(name, serialize_value(name, value))
101
+ end
102
+ end
103
+
104
+ def self.serialize_array(search_params, name, values)
105
+ # The parser reads a single pair with an empty value as an empty array.
106
+ if values.empty?
107
+ search_params.set(name, "")
108
+ return
109
+ end
110
+
111
+ values = values.map { |value| value.is_a?(Symbol) ? value.to_s : value }
112
+
113
+ if values.length == 1 && values.first == ""
114
+ raise UnserializableParamError.new(
115
+ name,
116
+ "is a single element array containing the empty string which is unsupported"
117
+ )
118
+ end
119
+
120
+ if values.any? { |value| value == "" }
121
+ raise UnserializableParamError.new(
122
+ name,
123
+ "is an array containing the empty string which is unsupported"
124
+ )
125
+ end
126
+
127
+ if values.any? { |value| value.nil? || value.is_a?(Seam::Null) }
128
+ raise UnserializableParamError.new(
129
+ name,
130
+ "is an array containing null or undefined values which is unsupported"
131
+ )
132
+ end
133
+
134
+ values.each { |value| search_params.append(name, serialize_value(name, value)) }
135
+ end
136
+
137
+ def self.serialize_value(name, value)
138
+ case value
139
+ when Seam::Null then ""
140
+ when String then value
141
+ when true, false then value.to_s
142
+ when Integer then value.to_s
143
+ when Float then serialize_float(name, value)
144
+ when Time then serialize_time(value)
145
+ when DateTime then serialize_time(value.to_time)
146
+ when Date then serialize_time(Time.utc(value.year, value.month, value.day))
147
+ else
148
+ raise UnserializableParamError.new(name, "is a #{value.class}")
149
+ end
150
+ end
151
+
152
+ # Formats a float exactly like ECMAScript Number::toString.
153
+ def self.serialize_float(name, value)
154
+ raise UnserializableParamError.new(name, "is NaN") if value.nan?
155
+ if value.infinite?
156
+ raise UnserializableParamError.new(name, "is #{value.positive? ? "Infinity" : "-Infinity"}")
157
+ end
158
+ return "0" if value.zero?
159
+
160
+ digits, point = shortest_decimal(value.abs)
161
+ count = digits.length
162
+
163
+ formatted = if point.between?(count, 21)
164
+ digits + "0" * (point - count)
165
+ elsif point.positive? && point <= 21
166
+ "#{digits[0, point]}.#{digits[point..]}"
167
+ elsif point > -6 && point <= 0
168
+ "0.#{"0" * -point}#{digits}"
169
+ else
170
+ mantissa = (count == 1) ? digits : "#{digits[0]}.#{digits[1..]}"
171
+ exponent = point - 1
172
+ "#{mantissa}e#{(exponent >= 0) ? "+" : "-"}#{exponent.abs}"
173
+ end
174
+
175
+ value.negative? ? "-#{formatted}" : formatted
176
+ end
177
+
178
+ # Returns the shortest round-tripping decimal digits of a positive float
179
+ # and the position of the decimal point relative to the first digit.
180
+ def self.shortest_decimal(value)
181
+ repr = value.to_s
182
+
183
+ if repr.include?("e")
184
+ mantissa, exponent = repr.split("e")
185
+ integer_part, fraction_part = mantissa.split(".")
186
+ digits = integer_part + (fraction_part || "")
187
+ point = integer_part.length + exponent.to_i
188
+ else
189
+ integer_part, fraction_part = repr.split(".")
190
+ digits = integer_part + (fraction_part || "")
191
+ point = integer_part.length
192
+ end
193
+
194
+ leading_zeros = digits[/\A0*/].length
195
+ digits = digits[leading_zeros..]
196
+ point -= leading_zeros
197
+
198
+ [digits.sub(/0+\z/, ""), point]
199
+ end
200
+
201
+ # Formats a time exactly like JavaScript's Date#toISOString.
202
+ def self.serialize_time(time)
203
+ utc = time.getutc
204
+ year = if utc.year.between?(0, 9999)
205
+ format("%04d", utc.year)
206
+ elsif utc.year > 9999
207
+ format("+%06d", utc.year)
208
+ else
209
+ format("-%06d", -utc.year)
210
+ end
211
+ format(
212
+ "%s-%02d-%02dT%02d:%02d:%02d.%03dZ",
213
+ year, utc.month, utc.day, utc.hour, utc.min, utc.sec, utc.nsec / 1_000_000
214
+ )
215
+ end
216
+ end
217
+ 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.140.0"
4
+ VERSION = "2.141.1"
5
5
  end
data/lib/seam.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "seam/null"
4
+ require_relative "seam/url_search_params"
5
+ require_relative "seam/strict_url_search_params_serializer"
3
6
  require_relative "seam/http"
4
7
  require_relative "seam/http_without_workspace"
5
8
  require_relative "seam/webhook"