From 5da951f421d857e976cecb48f2c204686eb5148b Mon Sep 17 00:00:00 2001 From: Evan Sosenko Date: Wed, 2 Jul 2025 13:24:42 -0700 Subject: [PATCH 1/3] fix: Filter resourceSamples on endpoints like on route --- src/lib/layout/api-endpoint.ts | 16 +++++++++++++- src/lib/layout/api-route.ts | 38 +++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/src/lib/layout/api-endpoint.ts b/src/lib/layout/api-endpoint.ts index 9a0e5b666..78d033a85 100644 --- a/src/lib/layout/api-endpoint.ts +++ b/src/lib/layout/api-endpoint.ts @@ -18,6 +18,7 @@ import { mapResourceSample, normalizePropertyFormatForDocs, type ResourceSampleContext, + resourceSampleFilter, } from './api-route.js' const supportedSdks: SdkName[] = [ @@ -189,6 +190,7 @@ export function setEndpointLayoutContext( endpoint, resources, actionAttempts, + pathMetadata, ).map(mapResourceSample) const [primaryCodeSample, ...additionalCodeSamples] = endpoint.codeSamples @@ -245,6 +247,7 @@ const getResourceSamples = ( endpoint: Endpoint, resources: Resource[], actionAttempts: ActionAttempt[], + pathMetadata: PathMetadata, ): ResourceSample[] => { const { response } = endpoint @@ -268,7 +271,18 @@ const getResourceSamples = ( if (resource == null) return [] - const sample = resource.resourceSamples[0] + const metadata = pathMetadata[resource.routePath] + if (metadata == null) { + throw new Error(`Missing path metadata for ${resource.routePath}`) + } + + const sample = resource.resourceSamples.filter( + resourceSampleFilter({ + include: metadata.include_groups, + exclude: metadata.exclude_groups, + }), + )[0] + if (sample == null) return [] return [ diff --git a/src/lib/layout/api-route.ts b/src/lib/layout/api-route.ts index c5afc46b2..1c90e2081 100644 --- a/src/lib/layout/api-route.ts +++ b/src/lib/layout/api-route.ts @@ -182,10 +182,7 @@ export const setApiRouteLayoutContext = ( ? groupProperties( legacyProperty.properties, legacyProperty.propertyGroups, - { - include: metadata.include_groups, - exclude: metadata.exclude_groups, - }, + groupOptions, ) : null @@ -199,24 +196,31 @@ export const setApiRouteLayoutContext = ( hidePreamble: route.path !== resource.routePath, events: eventsByRoutePath.get(resource.routePath) ?? [], resourceSamples: resource.resourceSamples - .filter(({ title }) => { - if (groupOptions.include != null) { - return groupOptions.include.some((x) => - title.toLowerCase().includes(x.split('_')[0]?.slice(0, -1) ?? ''), - ) - } - if (groupOptions.exclude != null) { - return !groupOptions.exclude.some((x) => - title.toLowerCase().includes(x.split('_')[0]?.slice(0, -1) ?? ''), - ) - } - return true - }) + .filter(resourceSampleFilter(groupOptions)) .map(mapResourceSample), }) } } +export const resourceSampleFilter = + (groupOptions: { + include: string[] | undefined + exclude?: string[] | undefined + }) => + ({ title }: ResourceSample): boolean => { + if (groupOptions.include != null) { + return groupOptions.include.some((x) => + title.toLowerCase().includes(x.split('_')[0]?.slice(0, -1) ?? ''), + ) + } + if (groupOptions.exclude != null) { + return !groupOptions.exclude.some((x) => + title.toLowerCase().includes(x.split('_')[0]?.slice(0, -1) ?? ''), + ) + } + return true + } + const groupVariants = ( property: Property | null, { From d925a0c9fc73701a5787cfc0d77bf799ea8d76d4 Mon Sep 17 00:00:00 2001 From: Evan Sosenko Date: Wed, 2 Jul 2025 16:57:26 -0700 Subject: [PATCH 2/3] Remove strict check --- src/lib/layout/api-endpoint.ts | 7 ++----- src/lib/layout/api-route.ts | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/lib/layout/api-endpoint.ts b/src/lib/layout/api-endpoint.ts index 78d033a85..ea726d84c 100644 --- a/src/lib/layout/api-endpoint.ts +++ b/src/lib/layout/api-endpoint.ts @@ -272,14 +272,11 @@ const getResourceSamples = ( if (resource == null) return [] const metadata = pathMetadata[resource.routePath] - if (metadata == null) { - throw new Error(`Missing path metadata for ${resource.routePath}`) - } const sample = resource.resourceSamples.filter( resourceSampleFilter({ - include: metadata.include_groups, - exclude: metadata.exclude_groups, + include: metadata?.include_groups, + exclude: metadata?.exclude_groups, }), )[0] diff --git a/src/lib/layout/api-route.ts b/src/lib/layout/api-route.ts index 1c90e2081..bacdbbe5b 100644 --- a/src/lib/layout/api-route.ts +++ b/src/lib/layout/api-route.ts @@ -205,7 +205,7 @@ export const setApiRouteLayoutContext = ( export const resourceSampleFilter = (groupOptions: { include: string[] | undefined - exclude?: string[] | undefined + exclude: string[] | undefined }) => ({ title }: ResourceSample): boolean => { if (groupOptions.include != null) { From f52d4786700e2ffa4612e18244efc66f254812be Mon Sep 17 00:00:00 2001 From: Mike Wu Date: Wed, 30 Jul 2025 20:26:04 +0700 Subject: [PATCH 3/3] fix: show thermostat sample for /thermostats/list (#766) * include parent metadata * ci: Generate docs * update to only select parent metadata * ci: Generate docs * fallback endpoint sample * ci: Generate docs --------- Co-authored-by: Seam Bot --- codegen/lib/layout/api-endpoint.ts | 18 ++- docs/api/noise_sensors/list.md | 101 +++++++++------- docs/api/thermostats/list.md | 188 +++++++++++++++++++++++------ 3 files changed, 223 insertions(+), 84 deletions(-) diff --git a/codegen/lib/layout/api-endpoint.ts b/codegen/lib/layout/api-endpoint.ts index 801621e67..4042d18d4 100644 --- a/codegen/lib/layout/api-endpoint.ts +++ b/codegen/lib/layout/api-endpoint.ts @@ -291,15 +291,25 @@ const getResourceSamples = ( if (resource == null) return [] - const metadata = pathMetadata[resource.routePath] + const endpointMetadata = pathMetadata[resource.routePath] + const endpointSample = resource.resourceSamples.filter( + resourceSampleFilter({ + include: endpointMetadata?.include_groups, + exclude: endpointMetadata?.exclude_groups, + }), + )[0] - const sample = resource.resourceSamples.filter( + const parentMetadata = + endpoint.parentPath != null ? pathMetadata[endpoint.parentPath] : undefined + const parentSample = resource.resourceSamples.filter( resourceSampleFilter({ - include: metadata?.include_groups, - exclude: metadata?.exclude_groups, + include: parentMetadata?.include_groups, + exclude: parentMetadata?.exclude_groups, }), )[0] + const sample = parentSample ?? endpointSample + if (sample == null) return [] return [ diff --git a/docs/api/noise_sensors/list.md b/docs/api/noise_sensors/list.md index 99260ec7c..c28fcbf27 100644 --- a/docs/api/noise_sensors/list.md +++ b/docs/api/noise_sensors/list.md @@ -712,55 +712,74 @@ Array of [devices](./../devices) ```json { - "can_program_online_access_codes": true, - "can_remotely_lock": true, - "can_remotely_unlock": true, - "capabilities_supported": ["access_code", "lock"], - "connected_account_id": "8e3a4f1b-2c7d-4a9e-8b5f-3d2c1a0b9e8f", - "created_at": "2025-03-27T02:08:16.418Z", + "capabilities_supported": ["noise_detection"], + "connected_account_id": "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d", + "created_at": "2025-05-16T16:54:17.946049Z", "custom_metadata": { "id": "internalId1" }, - "device_id": "a69569e1-133b-4a9d-b883-018641bfe543", - "device_type": "schlage_lock", - "display_name": "FRONT DOOR", + "device_id": "f1e2d3c4-b5a6-4d7c-8e9f-0a1b2c3d4e5f", + "device_type": "minut_sensor", + "display_name": "Living Room", "errors": [], "is_managed": true, - "location": { "location_name": "Front Door", "timezone": "America/New_York" }, - "nickname": "Front Door", + "location": { + "location_name": "Jane's Test Home", + "timezone": "America/Los_Angeles" + }, + "nickname": "Living Room", "properties": { - "appearance": { "name": "FRONT DOOR" }, - "battery": { "level": 0.48, "status": "good" }, - "battery_level": 0.48, - "code_constraints": [{ "constraint_type": "name_length", "max_length": 9 }], - "has_native_entry_events": true, - "image_alt_text": "Schlage Sense Smart Deadbolt with Camelot Trim, Front", - "image_url": "https://connect.getseam.com/_next/image?url=https://connect.getseam.com/assets/images/devices/schlage_sense-smart-deadbolt-with-camelot-trim_front.png&q=75&w=128", - "locked": false, - "manufacturer": "schlage", - "model": { - "accessory_keypad_supported": false, - "can_connect_accessory_keypad": false, - "display_name": "Encode", - "has_built_in_keypad": true, - "manufacturer_display_name": "Schlage", - "offline_access_codes_supported": false, - "online_access_codes_supported": true + "appearance": { "name": "Living Room" }, + "battery": { "level": 1, "status": "full" }, + "battery_level": 1, + "currently_triggering_noise_threshold_ids": [], + "image_alt_text": "Minut Sensor", + "image_url": "https://connect.getseam.com/_next/image?url=https://connect.getseam.com/assets/images/devices/minut_gen-3_front.png&q=75&w=128", + "manufacturer": "minut", + "minut_metadata": { + "device_id": "770cd3153deca3dee0fe0614", + "device_location": { "latitude": 0, "longitude": 0 }, + "device_name": "Living Room", + "home_address": { + "city": "San Francisco", + "country": "US", + "notes": "string", + "post_code": "44210", + "region": "San Francisco County", + "street_name1": "2258 24th Street", + "street_name2": "" + }, + "home_id": "2978b6d5dba395ec08300e46", + "home_location": { "latitude": 0, "longitude": 0 }, + "home_name": "Jane's Test Home", + "latest_sensor_values": { + "accelerometer_z": { + "time": "2025-06-16T16:54:17.946049Z", + "value": -1.00390625 + }, + "humidity": { + "time": "2025-06-16T16:54:17.946049Z", + "value": 31.110000610351562 + }, + "pressure": { "time": "2025-06-16T16:54:17.946049Z", "value": 101923 }, + "sound": { + "time": "2025-06-16T16:54:17.946049Z", + "value": 47.7117919921875 + }, + "temperature": { + "time": "2025-06-16T16:54:17.946049Z", + "value": 21.270000457763672 + } + } }, - "name": "FRONT DOOR", - "offline_access_codes_enabled": false, - "online": true, - "online_access_codes_enabled": true, - "schlage_metadata": { - "device_id": "a69569e1-133b-4a9d-b883-018641bfe543", - "device_name": "FRONT DOOR", - "model": "Encode" + "model": { + "display_name": "Noise Sensor", + "manufacturer_display_name": "Minut" }, - "serial_number": "34000000000531e0", - "supported_code_lengths": [4, 5, 6, 7, 8], - "supports_backup_access_code_pool": true, - "supports_offline_access_codes": false + "name": "Living Room", + "noise_level_decibels": 47.7117919921875, + "online": true }, "warnings": [], - "workspace_id": "5d7f2e1a-9c8b-4f3e-8d2c-1a0b9e8f7c6d" + "workspace_id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d" } ``` {% endtab %} diff --git a/docs/api/thermostats/list.md b/docs/api/thermostats/list.md index bf5be4cac..2d1492c29 100644 --- a/docs/api/thermostats/list.md +++ b/docs/api/thermostats/list.md @@ -1266,55 +1266,165 @@ Array of [devices](./../devices) ```json { - "can_program_online_access_codes": true, - "can_remotely_lock": true, - "can_remotely_unlock": true, - "capabilities_supported": ["access_code", "lock"], - "connected_account_id": "8e3a4f1b-2c7d-4a9e-8b5f-3d2c1a0b9e8f", - "created_at": "2025-03-27T02:08:16.418Z", + "can_hvac_cool": true, + "can_hvac_heat": true, + "can_hvac_heat_cool": true, + "can_turn_off_hvac": true, + "capabilities_supported": ["thermostat"], + "connected_account_id": "a0b1c2d3-e4f5-6a7b-8c9d-0e1f2a3b4c5d", + "created_at": "2024-10-03T22:12:15.666Z", "custom_metadata": { "id": "internalId1" }, - "device_id": "a69569e1-133b-4a9d-b883-018641bfe543", - "device_type": "schlage_lock", - "display_name": "FRONT DOOR", + "device_id": "a1b2c3d4-e5f6-7890-1234-56789abcdef0", + "device_type": "ecobee_thermostat", + "display_name": "Living Room", "errors": [], "is_managed": true, - "location": { "location_name": "Front Door", "timezone": "America/New_York" }, - "nickname": "Front Door", + "location": { + "location_name": "2948 20th St, San Francisco, CA, 94110, US", + "timezone": "America/Los_Angeles" + }, + "nickname": "Living Room", "properties": { - "appearance": { "name": "FRONT DOOR" }, - "battery": { "level": 0.48, "status": "good" }, - "battery_level": 0.48, - "code_constraints": [{ "constraint_type": "name_length", "max_length": 9 }], - "has_native_entry_events": true, - "image_alt_text": "Schlage Sense Smart Deadbolt with Camelot Trim, Front", - "image_url": "https://connect.getseam.com/_next/image?url=https://connect.getseam.com/assets/images/devices/schlage_sense-smart-deadbolt-with-camelot-trim_front.png&q=75&w=128", - "locked": false, - "manufacturer": "schlage", + "active_climate_preset": { + "can_delete": true, + "can_edit": true, + "climate_preset_key": "sleep", + "cooling_set_point_celsius": 23.88888888888889, + "display_name": "Sleep", + "fan_mode_setting": "auto", + "heating_set_point_celsius": 17.77777777777778, + "hvac_mode_setting": "heat_cool", + "manual_override_allowed": true + }, + "appearance": { "name": "Living Room" }, + "available_climate_presets": [ + { + "climate_preset_key": "sleep", + "can_edit": true, + "can_delete": true, + "can_program": false, + "name": "Sleep", + "display_name": "Sleep", + "fan_mode_setting": "auto", + "hvac_mode_setting": "heat_cool", + "manual_override_allowed": true, + "cooling_set_point_celsius": 23.88888888888889, + "heating_set_point_celsius": 17.77777777777778, + "cooling_set_point_fahrenheit": 75, + "heating_set_point_fahrenheit": 64 + }, + { + "climate_preset_key": "home", + "can_edit": true, + "can_delete": true, + "can_program": false, + "name": "Home", + "display_name": "Home", + "fan_mode_setting": "auto", + "hvac_mode_setting": "heat_cool", + "manual_override_allowed": false, + "cooling_set_point_celsius": 23.88888888888889, + "heating_set_point_celsius": 17.77777777777778, + "cooling_set_point_fahrenheit": 75, + "heating_set_point_fahrenheit": 64 + }, + { + "climate_preset_key": "work", + "can_edit": true, + "can_delete": true, + "can_program": false, + "name": "Work", + "display_name": "Work", + "fan_mode_setting": "auto", + "hvac_mode_setting": "heat_cool", + "manual_override_allowed": false, + "cooling_set_point_celsius": 23.88888888888889, + "heating_set_point_celsius": 17.77777777777778, + "cooling_set_point_fahrenheit": 75, + "heating_set_point_fahrenheit": 64 + } + ], + "available_fan_mode_settings": ["auto", "on"], + "available_hvac_mode_settings": ["cool", "heat", "heat_cool", "off"], + "current_climate_setting": { + "display_name": "Manual Setting", + "fan_mode_setting": "auto", + "heating_set_point_celsius": 25, + "heating_set_point_fahrenheit": 77, + "hvac_mode_setting": "heat", + "manual_override_allowed": true + }, + "ecobee_metadata": { + "device_name": "Living Room", + "ecobee_device_id": "a1b2c3d4-e5f6-7890-1234-56789abcdef0" + }, + "fallback_climate_preset_key": "eco", + "fan_mode_setting": "auto", + "has_direct_power": true, + "image_alt_text": "Ecobee 3 Lite Thermostat", + "image_url": "https://connect.getseam.com/_next/image?url=https://connect.getseam.com/assets/images/devices/ecobee_3-lite_front.png&q=75&w=128", + "is_cooling": false, + "is_fan_running": false, + "is_heating": false, + "is_temporary_manual_override_active": false, + "manufacturer": "ecobee", + "max_cooling_set_point_celsius": 33.333333333333336, + "max_cooling_set_point_fahrenheit": 92, + "max_heating_set_point_celsius": 26.11111111111111, + "max_heating_set_point_fahrenheit": 79, + "min_cooling_set_point_celsius": 18.333333333333336, + "min_cooling_set_point_fahrenheit": 65, + "min_heating_cooling_delta_celsius": 2.7777777777777777, + "min_heating_cooling_delta_fahrenheit": 5, + "min_heating_set_point_celsius": 7.222222222222222, + "min_heating_set_point_fahrenheit": 45, "model": { - "accessory_keypad_supported": false, - "can_connect_accessory_keypad": false, - "display_name": "Encode", - "has_built_in_keypad": true, - "manufacturer_display_name": "Schlage", - "offline_access_codes_supported": false, - "online_access_codes_supported": true + "display_name": "Thermostat", + "manufacturer_display_name": "Ecobee" }, - "name": "FRONT DOOR", - "offline_access_codes_enabled": false, + "name": "Living Room", "online": true, - "online_access_codes_enabled": true, - "schlage_metadata": { - "device_id": "a69569e1-133b-4a9d-b883-018641bfe543", - "device_name": "FRONT DOOR", - "model": "Encode" + "relative_humidity": 0.36, + "temperature_celsius": 21.11111111111111, + "temperature_fahrenheit": 70, + "temperature_threshold": { + "lower_limit_celsius": 16.66666666666667, + "lower_limit_fahrenheit": 62, + "upper_limit_celsius": 26.66666666666667, + "upper_limit_fahrenheit": 80 }, - "serial_number": "34000000000531e0", - "supported_code_lengths": [4, 5, 6, 7, 8], - "supports_backup_access_code_pool": true, - "supports_offline_access_codes": false + "thermostat_daily_programs": [ + { + "thermostat_daily_program_id": "1a2b3c4d-5e6f-7890-1234-56789abcdef1", + "device_id": "a1b2c3d4-e5f6-7890-1234-56789abcdef0", + "name": "Weekday Program", + "periods": [ + { "starts_at_time": "00:00:00", "climate_preset_key": "sleep" }, + { "starts_at_time": "07:00:00", "climate_preset_key": "home" }, + { "starts_at_time": "09:00:00", "climate_preset_key": "work" }, + { "starts_at_time": "18:00:00", "climate_preset_key": "home" }, + { "starts_at_time": "22:00:00", "climate_preset_key": "sleep" } + ], + "workspace_id": "9f8e7d6c-5b4a-3c2d-1e0f-9876543210ab", + "created_at": "2025-05-30T04:01:25.455Z" + }, + { + "thermostat_daily_program_id": "d4e5f6a7-8b9c-0d1e-2f3a-4b5c6d7e8f90", + "device_id": "a1b2c3d4-e5f6-7890-1234-56789abcdef0", + "name": "Weekend Program", + "periods": [ + { "starts_at_time": "00:00:00", "climate_preset_key": "sleep" }, + { "starts_at_time": "08:00:00", "climate_preset_key": "home" }, + { "starts_at_time": "23:00:00", "climate_preset_key": "sleep" } + ], + "workspace_id": "9f8e7d6c-5b4a-3c2d-1e0f-9876543210ab", + "created_at": "2025-05-30T04:02:19.952Z" + } + ], + "thermostat_weekly_program": null }, "warnings": [], - "workspace_id": "5d7f2e1a-9c8b-4f3e-8d2c-1a0b9e8f7c6d" + "workspace_id": "9f8e7d6c-5b4a-3c2d-1e0f-9876543210ab" } ``` {% endtab %}