Skip to content

feat: Add Ecosystem components (CompatibleApps, SupportedDevices) - #745

Merged
sybohy merged 1 commit into
mainfrom
sy/devdb-443-ecosystem-components
Oct 17, 2026
Merged

sybohy merged 1 commit into
mainfrom
sy/devdb-443-ecosystem-components

Conversation

@sybohy

@sybohy sybohy commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

Adds Seam Ecosystem (PartnerDB and DeviceDB) components to Seam Components, plus a lightweight ecosystem.js bundle for marketing and product pages.

Fixes DEVDB-443
Fixes DEVDB-444
Fixes DEVDB-445

What's new

CompatibleApps / <seam-compatible-apps> (DEVDB-444), ported from custom-device-db-web#43 and rebuilt in the repo's SCSS (seam- classes, global CSS injection) with light, dark and auto themes.

  • Data from GET /v1/compatibility (declared-first). Shows each partner's support note when provider or capability is set.
  • Attributes: device-type (required), manufacturer, provider, capability, industry, max-visible, hide-search, hide-title, theme.
  • Featured partners sort first, client-side search, a show-more button, plus loading, empty, error and invalid-key states. English only.

SupportedDevices / <seam-supported-devices> (DEVDB-445) brings back a DeviceDB component, now backed by Ecosystem GET /v1/device_models/list (all pages) and manufacturers/list for logos.

  • Device models grouped by manufacturer, with image, device type badge and capability badges. Conditionally supported capabilities get a dashed badge and a tooltip with the report details.
  • Search, plus manufacturer, device type and capability filters, using native selects. Collapsible manufacturer sections when there is more than one manufacturer.
  • Attributes: manufacturer, device-type, capability, hide-search, hide-filters, hide-title, theme.
  • Manufacturer key: defaults to the key's manufacturer through embed/resolve. It reads the optional manufacturer_context.manufacturer_slug (DEVDB-439, not shipped yet) and falls back to embed_key.manufacturer_slug when owner_kind is manufacturer, which Ecosystem already returns. An explicit manufacturer attribute wins.
  • Partner key: hides the partner's declared exclusions from embed/resolve, like <device-list-by-capability> (DEVDB-371). That covers excluded manufacturers and device types, unsupported providers, and capability exclusions for the capability being shown.

Foundation (DEVDB-443)

  • EcosystemProvider (no publishable key, no Seam API client). SeamProvider also gets embedKey and ecosystemEndpoint props (default https://ecosystem.seam.co/v1/), so React apps can drop the components in.
  • Hooks: useCompatiblePartners, useEcosystemDeviceModels, useEcosystemManufacturers, useEmbedKeyResolution. They send X-Embed-Key and don't retry 4xx errors.
  • Response types are hand-copied from seamapi/ecosystem public-types (origin/main 733edf3) in src/lib/seam/ecosystem/types.ts, so there's no zod dependency.
  • New Vite lib entry src/ecosystem.ts → dist/ecosystem.js, exported as @seamapi/react/ecosystem.js. It's built separately, so both bundles stay self-contained, and it's fully minified. elements.js also registers both elements. Elements that are already defined are skipped, so a page can load both bundles.
  • Boolean attributes on the Ecosystem elements work without a value (<seam-compatible-apps hide-search>), which r2wc would otherwise parse as false.
  • CI size check: npm run size runs in _build.yml after the build. It fails if ecosystem.js goes over 80 kB gzip or bundles the Seam API client.

Note: SeamProvider (via SeamQueryProvider) throws without a publishable key or client session token, so the Ecosystem elements use their own lightweight EcosystemProvider wrapper instead of sharing the SeamProvider wrapper.

Bundle size

Bundle Raw Gzip
dist/ecosystem.js (new) 208.5 kB 65.8 kB
dist/elements.js (before) 1,343.7 kB 275.0 kB
dist/elements.js (after, includes the Ecosystem elements) 1,380.4 kB 284.1 kB

ecosystem.js is React + react-dom + TanStack Query + r2wc + the two components. The CSS is still the shared index.min.css (65.5 kB raw / 8.9 kB gzip), injected from react.seam.co.

Usage

Plain HTML:

<seam-supported-devices
  embed-key="eco_live_your_embed_key"
  manufacturer="schlage"
></seam-supported-devices>
<seam-compatible-apps
  embed-key="eco_live_your_embed_key"
  device-type="smartlock"
  manufacturer="schlage"
></seam-compatible-apps>
<script
  type="module"
  src="https://react.seam.co/v/<version>/dist/ecosystem.js"
></script>

React:

import { CompatibleApps, EcosystemProvider, SupportedDevices } from '@seamapi/react'

export function ProductPage() {
  return (
    <EcosystemProvider embedKey='eco_live_your_embed_key'>
      <SupportedDevices manufacturer='schlage' />
      <CompatibleApps deviceType='smartlock' manufacturer='schlage' />
    </EcosystemProvider>
  )
}

The README documents attributes, hooks and CSP (connect-src https://ecosystem.seam.co; img-src https://seam-ecosystem-media.fly.storage.tigris.dev).

Storybook and tests: no real key or production data

  • .storybook/fake-ecosystem.js is a fake of the public Ecosystem API. It has fictional partners, sample device models and generated SVG images. It ports Ecosystem's declared-first resolveSupport and exclusionsFromSupportRows, its error shapes (embed_key_required, invalid_embed_key, origin_not_allowed, invalid_params) and its pagination.
  • It's served at /api/ecosystem: locally by the Storybook middleware, and on react.seam.co by api/fake-ecosystem.ts through a vercel.json rewrite placed before the /api/* rewrite. Requests stay same-origin, so the existing CSP is unchanged.
  • Stories under Ecosystem/:
    • CompatibleApps: Smartlocks, Schlage only, Thermostats for STR, Salto KS mobile keys, Show more, Dark mode, Without title or search, Empty, Invalid key (401), Missing key, Disallowed origin (403).
    • SupportedDevices: All devices, Single manufacturer, Manufacturer key, Thermostats, Mobile keys, Partner key, Dark mode, Without filters, Empty, Invalid key.
  • Tests start the fake on a local port (setupFakeEcosystem() in test/fixtures/ecosystem.tsx):
    • Component tests for filtering, search, show more, empty and error states, manufacturer and partner key behavior, and use inside SeamProvider.
    • Unit tests for the exclusion, capability and grouping logic and for manufacturer-key resolution.
    • A web component test that renders <seam-compatible-apps> from attributes.

Screenshots

Rendered headlessly against the fake API, from the local Storybook and from this PR's Vercel preview (no console or CSP errors). Live on the preview:
CompatibleApps and SupportedDevices. Screenshots are attached to DEVDB-444 and DEVDB-445.

  • CompatibleApps, Smartlocks: a grid of 10 partner cards (featured StayPilot first). Each card has a logo, the name and the industry. A search field sits at the top right.
  • CompatibleApps, Salto KS mobile keys: the same grid narrowed to partners whose declarations allow it, with notes such as "Residents unlock Salto KS doors from the Gatehouse app."
  • SupportedDevices, Single manufacturer (Schlage): a "Supported Schlage devices" title with device type and capability selects and search. One Schlage section lists 7 rows, each with an image, name, model number, "via Provider", and badges right-aligned (e.g., Smartlock, Remote unlock, Remote lock, Access codes, with dashed badges for conditional support).
  • SupportedDevices, All devices: 11 manufacturer sections, collapsed to 5 rows with "Show all 7 Schlage devices".
  • Dark mode: both components on a dark surface, with mono partner and manufacturer logos.
  • Invalid key: "The embed key is invalid or has been revoked." with no retry button.

Checks run locally

npm run lint, npm run typecheck, npm test (64 tests), npm run build, npm run size and npm run docs:build all pass.

Follow-ups (not in this PR)

  • Ecosystem device_models/list responses are large and uncompressed: about 70 kB per model, mostly variants[].marketplace_listings. Caddy sends no content-encoding, so a 500-model page is about 11.7 MB. A manufacturer's list will be slow on a product page until Ecosystem compresses responses or offers a slimmer list view, e.g., the manufacturer content API (DEVDB-437).

🤖 Generated with Claude Code

Add Seam Ecosystem (PartnerDB and DeviceDB) components for marketing and
product pages:

- CompatibleApps / <seam-compatible-apps>: the live partner apps that
  support a device type, manufacturer, provider or capability, from
  GET /v1/compatibility (declared-first), with per-partner notes.
- SupportedDevices / <seam-supported-devices>: device models grouped by
  manufacturer with device type and capability badges, search and
  filters, from GET /v1/device_models/list. Defaults to the manufacturer
  of a manufacturer embed key and hides a partner key's declared
  exclusions (GET /v1/embed/resolve).

Add EcosystemProvider, an embedKey and ecosystemEndpoint prop on
SeamProvider, react-query hooks that send X-Embed-Key, and Ecosystem
response types copied from seamapi/ecosystem public-types.

Add a lightweight dist/ecosystem.js bundle (@seamapi/react/ecosystem.js)
with only the Ecosystem elements and no Seam API client; elements.js also
defines them. CI checks its size.

Storybook and tests use a fake Ecosystem API (.storybook/fake-ecosystem.js,
served at /api/ecosystem), never a real embed key or production data.

Fixes DEVDB-443
Fixes DEVDB-444
Fixes DEVDB-445

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@sybohy
sybohy requested review from dawnho and razor-x as code owners October 16, 2026 23:49
@sybohy
sybohy removed request for dawnho and razor-x October 16, 2026 23:55
@sybohy
sybohy merged commit 9d9e46c into main Oct 17, 2026
13 checks passed
@sybohy
sybohy deleted the sy/devdb-443-ecosystem-components branch October 17, 2026 07:20

This branch was successfully deployed

1 active deployment
Preview — a6fa51ed Deployed Oct 16, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant