@seamapi/react 5.0.0 → 5.1.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.
- package/README.md +111 -2
- package/dist/ecosystem.js +45 -0
- package/dist/ecosystem.js.map +1 -0
- package/dist/elements.js +12872 -11737
- package/dist/elements.js.map +1 -1
- package/dist/index.css +469 -0
- package/dist/index.css.map +1 -1
- package/dist/index.min.css +1 -1
- package/dist/index.min.css.map +1 -1
- package/lib/seam/SeamProvider.d.ts +10 -3
- package/lib/seam/SeamProvider.js +5 -3
- package/lib/seam/SeamProvider.js.map +1 -1
- package/lib/seam/components/CompatibleApps/CompatibleApps.d.ts +26 -0
- package/lib/seam/components/CompatibleApps/CompatibleApps.js +126 -0
- package/lib/seam/components/CompatibleApps/CompatibleApps.js.map +1 -0
- package/lib/seam/components/SupportedDevices/DeviceModelRow.d.ts +8 -0
- package/lib/seam/components/SupportedDevices/DeviceModelRow.js +31 -0
- package/lib/seam/components/SupportedDevices/DeviceModelRow.js.map +1 -0
- package/lib/seam/components/SupportedDevices/FilterSelect.d.ts +12 -0
- package/lib/seam/components/SupportedDevices/FilterSelect.js +9 -0
- package/lib/seam/components/SupportedDevices/FilterSelect.js.map +1 -0
- package/lib/seam/components/SupportedDevices/ManufacturerSection.d.ts +10 -0
- package/lib/seam/components/SupportedDevices/ManufacturerSection.js +35 -0
- package/lib/seam/components/SupportedDevices/ManufacturerSection.js.map +1 -0
- package/lib/seam/components/SupportedDevices/SupportedDevices.d.ts +24 -0
- package/lib/seam/components/SupportedDevices/SupportedDevices.js +151 -0
- package/lib/seam/components/SupportedDevices/SupportedDevices.js.map +1 -0
- package/lib/seam/components/SupportedDevices/device-models.d.ts +47 -0
- package/lib/seam/components/SupportedDevices/device-models.js +217 -0
- package/lib/seam/components/SupportedDevices/device-models.js.map +1 -0
- package/lib/seam/components/index.d.ts +2 -0
- package/lib/seam/components/index.js +2 -0
- package/lib/seam/components/index.js.map +1 -1
- package/lib/seam/ecosystem/EcosystemProvider.d.ts +37 -0
- package/lib/seam/ecosystem/EcosystemProvider.js +56 -0
- package/lib/seam/ecosystem/EcosystemProvider.js.map +1 -0
- package/lib/seam/ecosystem/client.d.ts +28 -0
- package/lib/seam/ecosystem/client.js +74 -0
- package/lib/seam/ecosystem/client.js.map +1 -0
- package/lib/seam/ecosystem/index.d.ts +9 -0
- package/lib/seam/ecosystem/index.js +8 -0
- package/lib/seam/ecosystem/index.js.map +1 -0
- package/lib/seam/ecosystem/types.d.ts +312 -0
- package/lib/seam/ecosystem/types.js +10 -0
- package/lib/seam/ecosystem/types.js.map +1 -0
- package/lib/seam/ecosystem/use-compatible-partners.d.ts +21 -0
- package/lib/seam/ecosystem/use-compatible-partners.js +36 -0
- package/lib/seam/ecosystem/use-compatible-partners.js.map +1 -0
- package/lib/seam/ecosystem/use-ecosystem-device-model-summaries.d.ts +11 -0
- package/lib/seam/ecosystem/use-ecosystem-device-model-summaries.js +53 -0
- package/lib/seam/ecosystem/use-ecosystem-device-model-summaries.js.map +1 -0
- package/lib/seam/ecosystem/use-ecosystem-device-models.d.ts +20 -0
- package/lib/seam/ecosystem/use-ecosystem-device-models.js +51 -0
- package/lib/seam/ecosystem/use-ecosystem-device-models.js.map +1 -0
- package/lib/seam/ecosystem/use-ecosystem-manufacturers.d.ts +11 -0
- package/lib/seam/ecosystem/use-ecosystem-manufacturers.js +49 -0
- package/lib/seam/ecosystem/use-ecosystem-manufacturers.js.map +1 -0
- package/lib/seam/ecosystem/use-ecosystem-query-result.d.ts +7 -0
- package/lib/seam/ecosystem/use-ecosystem-query-result.js +7 -0
- package/lib/seam/ecosystem/use-ecosystem-query-result.js.map +1 -0
- package/lib/seam/ecosystem/use-embed-key-resolution.d.ts +20 -0
- package/lib/seam/ecosystem/use-embed-key-resolution.js +51 -0
- package/lib/seam/ecosystem/use-embed-key-resolution.js.map +1 -0
- package/lib/seam/index.d.ts +1 -0
- package/lib/seam/index.js +1 -0
- package/lib/seam/index.js.map +1 -1
- package/lib/seam/seam-components-class-name.d.ts +1 -0
- package/lib/seam/seam-components-class-name.js +2 -0
- package/lib/seam/seam-components-class-name.js.map +1 -0
- package/lib/ui/ecosystem/SearchField.d.ts +9 -0
- package/lib/ui/ecosystem/SearchField.js +8 -0
- package/lib/ui/ecosystem/SearchField.js.map +1 -0
- package/lib/ui/ecosystem/StateMessage.d.ts +8 -0
- package/lib/ui/ecosystem/StateMessage.js +5 -0
- package/lib/ui/ecosystem/StateMessage.js.map +1 -0
- package/lib/ui/ecosystem/errors.d.ts +5 -0
- package/lib/ui/ecosystem/errors.js +25 -0
- package/lib/ui/ecosystem/errors.js.map +1 -0
- package/lib/ui/ecosystem/storybook.d.ts +15 -0
- package/lib/ui/ecosystem/storybook.js +16 -0
- package/lib/ui/ecosystem/storybook.js.map +1 -0
- package/lib/ui/ecosystem/theme.d.ts +6 -0
- package/lib/ui/ecosystem/theme.js +11 -0
- package/lib/ui/ecosystem/theme.js.map +1 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +11 -3
- package/src/ecosystem.d.ts +2 -0
- package/src/ecosystem.ts +12 -0
- package/src/elements.ts +4 -0
- package/src/lib/ecosystem-element.tsx +154 -0
- package/src/lib/element.tsx +6 -0
- package/src/lib/seam/SeamProvider.tsx +18 -2
- package/src/lib/seam/components/CompatibleApps/CompatibleApps.element.ts +19 -0
- package/src/lib/seam/components/CompatibleApps/CompatibleApps.tsx +344 -0
- package/src/lib/seam/components/SupportedDevices/DeviceModelRow.tsx +108 -0
- package/src/lib/seam/components/SupportedDevices/FilterSelect.tsx +43 -0
- package/src/lib/seam/components/SupportedDevices/ManufacturerSection.tsx +114 -0
- package/src/lib/seam/components/SupportedDevices/SupportedDevices.element.ts +17 -0
- package/src/lib/seam/components/SupportedDevices/SupportedDevices.tsx +382 -0
- package/src/lib/seam/components/SupportedDevices/device-models.ts +326 -0
- package/src/lib/seam/components/ecosystem-elements.ts +2 -0
- package/src/lib/seam/components/index.ts +2 -0
- package/src/lib/seam/ecosystem/EcosystemProvider.tsx +133 -0
- package/src/lib/seam/ecosystem/client.ts +116 -0
- package/src/lib/seam/ecosystem/index.ts +19 -0
- package/src/lib/seam/ecosystem/types.ts +402 -0
- package/src/lib/seam/ecosystem/use-compatible-partners.ts +80 -0
- package/src/lib/seam/ecosystem/use-ecosystem-device-model-summaries.ts +89 -0
- package/src/lib/seam/ecosystem/use-ecosystem-device-models.ts +96 -0
- package/src/lib/seam/ecosystem/use-ecosystem-manufacturers.ts +86 -0
- package/src/lib/seam/ecosystem/use-ecosystem-query-result.ts +19 -0
- package/src/lib/seam/ecosystem/use-embed-key-resolution.ts +80 -0
- package/src/lib/seam/index.ts +1 -0
- package/src/lib/seam/seam-components-class-name.ts +1 -0
- package/src/lib/ui/ecosystem/SearchField.tsx +32 -0
- package/src/lib/ui/ecosystem/StateMessage.tsx +29 -0
- package/src/lib/ui/ecosystem/errors.ts +30 -0
- package/src/lib/ui/ecosystem/storybook.tsx +40 -0
- package/src/lib/ui/ecosystem/theme.ts +14 -0
- package/src/lib/version.ts +1 -1
- package/src/styles/_compatible-apps.scss +102 -0
- package/src/styles/_ecosystem.scss +295 -0
- package/src/styles/_main.scss +6 -0
- package/src/styles/_supported-devices.scss +153 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export * from './AccessCodeDetails/AccessCodeDetails.js'
|
|
2
2
|
export * from './AccessCodeTable/AccessCodeTable.js'
|
|
3
3
|
export * from './common-props.js'
|
|
4
|
+
export * from './CompatibleApps/CompatibleApps.js'
|
|
4
5
|
export * from './ConnectAccountButton/ConnectAccountButton.js'
|
|
5
6
|
export * from './CreateAccessCodeForm/CreateAccessCodeForm.js'
|
|
6
7
|
export * from './DeviceDetails/DeviceDetails.js'
|
|
7
8
|
export * from './DeviceTable/DeviceTable.js'
|
|
8
9
|
export * from './EditAccessCodeForm/EditAccessCodeForm.js'
|
|
10
|
+
export * from './SupportedDevices/SupportedDevices.js'
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import {
|
|
2
|
+
QueryClient,
|
|
3
|
+
QueryClientContext,
|
|
4
|
+
QueryClientProvider,
|
|
5
|
+
} from '@tanstack/react-query'
|
|
6
|
+
import {
|
|
7
|
+
createContext,
|
|
8
|
+
type PropsWithChildren,
|
|
9
|
+
useContext,
|
|
10
|
+
useMemo,
|
|
11
|
+
} from 'react'
|
|
12
|
+
|
|
13
|
+
import { defaultEcosystemEndpoint } from 'lib/seam/ecosystem/client.js'
|
|
14
|
+
import { seamComponentsClassName } from 'lib/seam/seam-components-class-name.js'
|
|
15
|
+
import { useSeamFont } from 'lib/seam/use-seam-font.js'
|
|
16
|
+
import { useSeamStyles } from 'lib/seam/use-seam-styles.js'
|
|
17
|
+
|
|
18
|
+
export interface EcosystemContext {
|
|
19
|
+
/** The embed key sent as `X-Embed-Key`, if any. */
|
|
20
|
+
embedKey: string | undefined
|
|
21
|
+
/** The Ecosystem API endpoint, ending in `/`. */
|
|
22
|
+
endpoint: string
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface EcosystemOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Seam Ecosystem embed key (`eco_live_…`).
|
|
28
|
+
* Required outside seam.co: the key's allowed origins must include the page origin.
|
|
29
|
+
*/
|
|
30
|
+
embedKey?: string | undefined
|
|
31
|
+
/** Seam Ecosystem API endpoint. Defaults to `https://ecosystem.seam.co/v1/`. */
|
|
32
|
+
ecosystemEndpoint?: string | undefined
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface EcosystemProviderProps
|
|
36
|
+
extends EcosystemOptions,
|
|
37
|
+
PropsWithChildren {
|
|
38
|
+
queryClient?: QueryClient | undefined
|
|
39
|
+
disableCssInjection?: boolean | undefined
|
|
40
|
+
disableFontInjection?: boolean | undefined
|
|
41
|
+
unminifiyCss?: boolean | undefined
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const defaultQueryClient = new QueryClient()
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Provides the Seam Ecosystem context for `CompatibleApps` and `SupportedDevices`.
|
|
48
|
+
*
|
|
49
|
+
* Unlike `SeamProvider`, this does not need a Seam publishable key
|
|
50
|
+
* and does not load the Seam API client, so it stays lightweight.
|
|
51
|
+
* Inside a `SeamProvider`, pass `embedKey` to the `SeamProvider` instead.
|
|
52
|
+
*/
|
|
53
|
+
export function EcosystemProvider({
|
|
54
|
+
children,
|
|
55
|
+
queryClient,
|
|
56
|
+
disableCssInjection = false,
|
|
57
|
+
disableFontInjection = false,
|
|
58
|
+
unminifiyCss = false,
|
|
59
|
+
...options
|
|
60
|
+
}: EcosystemProviderProps): JSX.Element {
|
|
61
|
+
useSeamStyles({ disabled: disableCssInjection, unminified: unminifiyCss })
|
|
62
|
+
useSeamFont({ disabled: disableFontInjection })
|
|
63
|
+
|
|
64
|
+
const queryClientFromContext = useContext(QueryClientContext)
|
|
65
|
+
|
|
66
|
+
return (
|
|
67
|
+
<div className={seamComponentsClassName}>
|
|
68
|
+
<QueryClientProvider
|
|
69
|
+
client={
|
|
70
|
+
queryClient ??
|
|
71
|
+
queryClientFromContext ??
|
|
72
|
+
globalThis.seamQueryClient ??
|
|
73
|
+
defaultQueryClient
|
|
74
|
+
}
|
|
75
|
+
>
|
|
76
|
+
<EcosystemContextProvider {...options}>
|
|
77
|
+
{children}
|
|
78
|
+
</EcosystemContextProvider>
|
|
79
|
+
</QueryClientProvider>
|
|
80
|
+
</div>
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Provides only the Ecosystem context; used by `SeamProvider`.
|
|
86
|
+
* Unset options inherit from an enclosing provider.
|
|
87
|
+
*/
|
|
88
|
+
export function EcosystemContextProvider({
|
|
89
|
+
children,
|
|
90
|
+
embedKey,
|
|
91
|
+
ecosystemEndpoint,
|
|
92
|
+
}: EcosystemOptions & PropsWithChildren): JSX.Element {
|
|
93
|
+
const parent = useContext(ecosystemContext)
|
|
94
|
+
|
|
95
|
+
const value = useMemo(
|
|
96
|
+
() => ({
|
|
97
|
+
embedKey: normalizeEmbedKey(embedKey) ?? parent.embedKey,
|
|
98
|
+
endpoint: normalizeEndpoint(ecosystemEndpoint) ?? parent.endpoint,
|
|
99
|
+
}),
|
|
100
|
+
[embedKey, ecosystemEndpoint, parent]
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<ecosystemContext.Provider value={value}>
|
|
105
|
+
{children}
|
|
106
|
+
</ecosystemContext.Provider>
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function useEcosystemContext(): EcosystemContext {
|
|
111
|
+
return useContext(ecosystemContext)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const normalizeEmbedKey = (
|
|
115
|
+
embedKey: string | undefined
|
|
116
|
+
): string | undefined => {
|
|
117
|
+
const key = embedKey?.trim()
|
|
118
|
+
if (key == null || key.length === 0) return undefined
|
|
119
|
+
return key
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const normalizeEndpoint = (
|
|
123
|
+
endpoint: string | undefined
|
|
124
|
+
): string | undefined => {
|
|
125
|
+
const value = endpoint?.trim()
|
|
126
|
+
if (value == null || value.length === 0) return undefined
|
|
127
|
+
return value.endsWith('/') ? value : `${value}/`
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const ecosystemContext = createContext<EcosystemContext>({
|
|
131
|
+
embedKey: undefined,
|
|
132
|
+
endpoint: defaultEcosystemEndpoint,
|
|
133
|
+
})
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { EcosystemErrorResponse } from './types.js'
|
|
2
|
+
|
|
3
|
+
export const defaultEcosystemEndpoint = 'https://ecosystem.seam.co/v1/'
|
|
4
|
+
|
|
5
|
+
export type EcosystemQueryParams = Record<
|
|
6
|
+
string,
|
|
7
|
+
string | number | boolean | string[] | null | undefined
|
|
8
|
+
>
|
|
9
|
+
|
|
10
|
+
export interface EcosystemRequestOptions {
|
|
11
|
+
endpoint: string
|
|
12
|
+
embedKey?: string | undefined
|
|
13
|
+
params?: EcosystemQueryParams
|
|
14
|
+
signal?: AbortSignal
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* An error response from the Ecosystem API.
|
|
19
|
+
* The `type` is the API error type, e.g., `embed_key_required`,
|
|
20
|
+
* `invalid_embed_key` or `origin_not_allowed`.
|
|
21
|
+
*/
|
|
22
|
+
export class EcosystemApiError extends Error {
|
|
23
|
+
readonly status: number
|
|
24
|
+
readonly type: string
|
|
25
|
+
readonly requestId: string | null
|
|
26
|
+
|
|
27
|
+
constructor({
|
|
28
|
+
status,
|
|
29
|
+
type,
|
|
30
|
+
message,
|
|
31
|
+
requestId = null,
|
|
32
|
+
}: {
|
|
33
|
+
status: number
|
|
34
|
+
type: string
|
|
35
|
+
message: string
|
|
36
|
+
requestId?: string | null
|
|
37
|
+
}) {
|
|
38
|
+
super(message)
|
|
39
|
+
this.name = 'EcosystemApiError'
|
|
40
|
+
this.status = status
|
|
41
|
+
this.type = type
|
|
42
|
+
this.requestId = requestId
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** True when the error means the embed key is missing, invalid or not allowed here. */
|
|
47
|
+
export const isEmbedKeyError = (error: unknown): boolean =>
|
|
48
|
+
error instanceof EcosystemApiError &&
|
|
49
|
+
(error.status === 401 || error.status === 403)
|
|
50
|
+
|
|
51
|
+
export const getEcosystemUrl = (
|
|
52
|
+
endpoint: string,
|
|
53
|
+
path: string,
|
|
54
|
+
params: EcosystemQueryParams = {}
|
|
55
|
+
): URL => {
|
|
56
|
+
const base = endpoint.endsWith('/') ? endpoint : `${endpoint}/`
|
|
57
|
+
const url = new URL(path, new URL(base, globalThis.location?.href))
|
|
58
|
+
for (const [key, value] of Object.entries(params)) {
|
|
59
|
+
if (value == null) continue
|
|
60
|
+
if (Array.isArray(value)) {
|
|
61
|
+
if (value.length === 0) continue
|
|
62
|
+
url.searchParams.set(key, value.join(','))
|
|
63
|
+
continue
|
|
64
|
+
}
|
|
65
|
+
if (typeof value === 'string' && value.length === 0) continue
|
|
66
|
+
url.searchParams.set(key, String(value))
|
|
67
|
+
}
|
|
68
|
+
return url
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const fetchEcosystem = async <T>(
|
|
72
|
+
path: string,
|
|
73
|
+
{ endpoint, embedKey, params, signal }: EcosystemRequestOptions
|
|
74
|
+
): Promise<T> => {
|
|
75
|
+
const url = getEcosystemUrl(endpoint, path, params)
|
|
76
|
+
|
|
77
|
+
const headers: Record<string, string> = { Accept: 'application/json' }
|
|
78
|
+
if (embedKey != null && embedKey.length > 0) {
|
|
79
|
+
headers['X-Embed-Key'] = embedKey
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const res = await globalThis.fetch(url, {
|
|
83
|
+
headers,
|
|
84
|
+
...(signal == null ? {} : { signal }),
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
const body = (await res.json().catch(() => null)) as unknown
|
|
88
|
+
|
|
89
|
+
if (!res.ok) {
|
|
90
|
+
const error = isErrorResponse(body) ? body.error : null
|
|
91
|
+
throw new EcosystemApiError({
|
|
92
|
+
status: res.status,
|
|
93
|
+
type: error?.type ?? 'unknown_error',
|
|
94
|
+
message:
|
|
95
|
+
error?.message ?? `Ecosystem request failed with status ${res.status}`,
|
|
96
|
+
requestId: error?.request_id ?? null,
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (body == null || typeof body !== 'object') {
|
|
101
|
+
throw new EcosystemApiError({
|
|
102
|
+
status: res.status,
|
|
103
|
+
type: 'invalid_response',
|
|
104
|
+
message: 'Ecosystem returned an invalid response',
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return body as T
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const isErrorResponse = (body: unknown): body is EcosystemErrorResponse =>
|
|
112
|
+
body != null &&
|
|
113
|
+
typeof body === 'object' &&
|
|
114
|
+
'error' in body &&
|
|
115
|
+
body.error != null &&
|
|
116
|
+
typeof body.error === 'object'
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export {
|
|
2
|
+
defaultEcosystemEndpoint,
|
|
3
|
+
EcosystemApiError,
|
|
4
|
+
isEmbedKeyError,
|
|
5
|
+
} from './client.js'
|
|
6
|
+
export {
|
|
7
|
+
type EcosystemContext,
|
|
8
|
+
type EcosystemOptions,
|
|
9
|
+
EcosystemProvider,
|
|
10
|
+
type EcosystemProviderProps,
|
|
11
|
+
useEcosystemContext,
|
|
12
|
+
} from './EcosystemProvider.js'
|
|
13
|
+
export * from './types.js'
|
|
14
|
+
export * from './use-compatible-partners.js'
|
|
15
|
+
export * from './use-ecosystem-device-models.js'
|
|
16
|
+
export * from './use-ecosystem-manufacturers.js'
|
|
17
|
+
export type { UseEcosystemQueryResult } from './use-ecosystem-query-result.js'
|
|
18
|
+
export * from './use-embed-key-resolution.js'
|
|
19
|
+
export type { EcosystemTheme } from 'lib/ui/ecosystem/theme.js'
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Response types for the public Seam Ecosystem API (PartnerDB and DeviceDB).
|
|
3
|
+
*
|
|
4
|
+
* Hand-copied from the zod schemas in `seamapi/ecosystem` `public-types/`
|
|
5
|
+
* (origin/main 055335c, 2026-10-17) to avoid a zod runtime dependency.
|
|
6
|
+
* Fields stored verbatim from the source as JSON are typed as `unknown`.
|
|
7
|
+
* Keep in sync with Ecosystem until it publishes its types as a package.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// Partners (PartnerDB)
|
|
11
|
+
|
|
12
|
+
export interface EcosystemIndustry {
|
|
13
|
+
industry_id: string
|
|
14
|
+
slug: string
|
|
15
|
+
display_name: string
|
|
16
|
+
short_name: string | null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface EcosystemSolution {
|
|
20
|
+
solution_id: string
|
|
21
|
+
slug: string
|
|
22
|
+
display_name: string
|
|
23
|
+
short_name: string | null
|
|
24
|
+
type: 'software' | 'service'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type PartnerAssetKind =
|
|
28
|
+
| 'square_logo'
|
|
29
|
+
| 'square_logo_mono'
|
|
30
|
+
| 'horizontal_logo'
|
|
31
|
+
| 'horizontal_logo_mono'
|
|
32
|
+
| 'product_image'
|
|
33
|
+
|
|
34
|
+
export interface PartnerAsset {
|
|
35
|
+
partner_asset_id: string
|
|
36
|
+
kind: PartnerAssetKind
|
|
37
|
+
url: string
|
|
38
|
+
mime: string
|
|
39
|
+
width: number | null
|
|
40
|
+
height: number | null
|
|
41
|
+
sort_order: number
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface Partner {
|
|
45
|
+
partner_id: string
|
|
46
|
+
slug: string
|
|
47
|
+
display_name: string
|
|
48
|
+
website: string | null
|
|
49
|
+
description_md: string | null
|
|
50
|
+
is_live: boolean
|
|
51
|
+
is_featured: boolean
|
|
52
|
+
legacy_industry_featured: boolean
|
|
53
|
+
industries: EcosystemIndustry[]
|
|
54
|
+
solutions: EcosystemSolution[]
|
|
55
|
+
assets: PartnerAsset[]
|
|
56
|
+
created_at: string
|
|
57
|
+
updated_at: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type SupportLevel =
|
|
61
|
+
| 'device_category'
|
|
62
|
+
| 'manufacturer'
|
|
63
|
+
| 'provider'
|
|
64
|
+
| 'capability'
|
|
65
|
+
|
|
66
|
+
export type ObservedStatus = 'active' | 'trace' | 'none' | 'unknown'
|
|
67
|
+
|
|
68
|
+
export type DeclaredStatus = 'enabled' | 'disabled' | 'not_via_seam'
|
|
69
|
+
|
|
70
|
+
export interface SupportResolution {
|
|
71
|
+
supported: boolean
|
|
72
|
+
resolved_level: SupportLevel | null
|
|
73
|
+
declared_status: DeclaredStatus | null
|
|
74
|
+
observed_status: ObservedStatus | null
|
|
75
|
+
note: string | null
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface CompatiblePartner extends Partner {
|
|
79
|
+
support: SupportResolution
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Embed keys
|
|
83
|
+
|
|
84
|
+
export type EmbedKeyOwnerKind = 'partner' | 'manufacturer' | 'seam'
|
|
85
|
+
|
|
86
|
+
/** The public record of an embed key, as returned by `embed/resolve`. */
|
|
87
|
+
export interface EmbedKey {
|
|
88
|
+
embed_key_id: string
|
|
89
|
+
display_name: string
|
|
90
|
+
owner_kind: EmbedKeyOwnerKind
|
|
91
|
+
partner_id: string | null
|
|
92
|
+
manufacturer_slug: string | null
|
|
93
|
+
allowed_origins: string[]
|
|
94
|
+
config: Record<string, unknown>
|
|
95
|
+
revoked_at: string | null
|
|
96
|
+
created_at: string
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface EmbedCapabilityExclusion {
|
|
100
|
+
device_category: string
|
|
101
|
+
/** Empty means every manufacturer in the category. */
|
|
102
|
+
manufacturer_slug: string
|
|
103
|
+
/** Empty means every provider in the category. */
|
|
104
|
+
provider_slug: string
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface EmbedExclusions {
|
|
108
|
+
excluded_manufacturers: string[]
|
|
109
|
+
excluded_device_types: string[]
|
|
110
|
+
unsupported_providers: string[]
|
|
111
|
+
capability: string
|
|
112
|
+
capability_exclusions: EmbedCapabilityExclusion[]
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** The manufacturer a manufacturer-owned key scopes DeviceDB widgets to (DEVDB-439). */
|
|
116
|
+
export interface EmbedManufacturerContext {
|
|
117
|
+
manufacturer_slug: string
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface EmbedResolution {
|
|
121
|
+
embed_key: EmbedKey
|
|
122
|
+
/** Set for manufacturer-owned keys; null for partner and Seam keys. */
|
|
123
|
+
manufacturer_context?: EmbedManufacturerContext | null
|
|
124
|
+
exclusions: EmbedExclusions
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Devices (DeviceDB)
|
|
128
|
+
|
|
129
|
+
export interface MediaFormat {
|
|
130
|
+
object_key: string
|
|
131
|
+
url: string
|
|
132
|
+
mime: string | null
|
|
133
|
+
width: number | null
|
|
134
|
+
height: number | null
|
|
135
|
+
bytes: number | null
|
|
136
|
+
sha256: string | null
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export type MediaFormatName = 'thumbnail' | 'small' | 'medium' | 'large'
|
|
140
|
+
|
|
141
|
+
export type DeviceAssetKind =
|
|
142
|
+
| 'square_logo'
|
|
143
|
+
| 'square_logo_mono'
|
|
144
|
+
| 'horizontal_logo'
|
|
145
|
+
| 'horizontal_logo_mono'
|
|
146
|
+
| 'default_device_image'
|
|
147
|
+
| 'featured'
|
|
148
|
+
| 'variant_image'
|
|
149
|
+
|
|
150
|
+
export interface DeviceAsset {
|
|
151
|
+
asset_id: string
|
|
152
|
+
kind: DeviceAssetKind
|
|
153
|
+
object_key: string
|
|
154
|
+
url: string
|
|
155
|
+
mime: string | null
|
|
156
|
+
width: number | null
|
|
157
|
+
height: number | null
|
|
158
|
+
bytes: number | null
|
|
159
|
+
sha256: string | null
|
|
160
|
+
sort_order: number
|
|
161
|
+
formats: Partial<Record<MediaFormatName, MediaFormat>>
|
|
162
|
+
created_at: string
|
|
163
|
+
updated_at: string
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export interface DeviceTypeRef {
|
|
167
|
+
device_type_id: string
|
|
168
|
+
slug: string
|
|
169
|
+
display_name: string
|
|
170
|
+
is_accessory: boolean
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export interface ManufacturerRef {
|
|
174
|
+
manufacturer_id: string
|
|
175
|
+
slug: string
|
|
176
|
+
display_name: string | null
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface ProviderRef {
|
|
180
|
+
provider_id: string
|
|
181
|
+
slug: string
|
|
182
|
+
display_name: string | null
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
export type CapabilityName =
|
|
186
|
+
| 'device_connectivity'
|
|
187
|
+
| 'can_program_online_access_codes'
|
|
188
|
+
| 'can_program_offline_access_codes'
|
|
189
|
+
| 'can_remotely_unlock'
|
|
190
|
+
| 'can_remotely_lock'
|
|
191
|
+
| 'can_encode_plastic_cards'
|
|
192
|
+
| 'can_provision_mobile_keys'
|
|
193
|
+
| 'can_provision_wallet_keys'
|
|
194
|
+
| 'can_hvac_cool'
|
|
195
|
+
| 'can_hvac_heat'
|
|
196
|
+
| 'can_hvac_auto'
|
|
197
|
+
| 'can_hvac_fan'
|
|
198
|
+
| 'can_program_thermostat_weekly_programs'
|
|
199
|
+
| 'can_monitor'
|
|
200
|
+
|
|
201
|
+
export type CapabilitySupported = 'yes' | 'no' | 'conditionally'
|
|
202
|
+
|
|
203
|
+
export type IntegrationSupportLevel =
|
|
204
|
+
| 'inquire'
|
|
205
|
+
| 'unavailable'
|
|
206
|
+
| 'planned'
|
|
207
|
+
| 'in-progress'
|
|
208
|
+
| 'beta'
|
|
209
|
+
| 'stable'
|
|
210
|
+
|
|
211
|
+
export interface CapabilityReport {
|
|
212
|
+
details: string
|
|
213
|
+
requirements?: Record<
|
|
214
|
+
string,
|
|
215
|
+
{ message: string; device_slugs?: string[]; [key: string]: unknown }
|
|
216
|
+
>
|
|
217
|
+
dependencies?: string[]
|
|
218
|
+
[key: string]: unknown
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export interface CapabilityDetail {
|
|
222
|
+
capability_id: string
|
|
223
|
+
name: CapabilityName
|
|
224
|
+
supported: CapabilitySupported
|
|
225
|
+
integration_support_level: IntegrationSupportLevel | null
|
|
226
|
+
report: CapabilityReport | null
|
|
227
|
+
report_raw: CapabilityReport | null
|
|
228
|
+
locale: string
|
|
229
|
+
computed_at: string
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export interface ProviderCapabilities {
|
|
233
|
+
provider: ProviderRef
|
|
234
|
+
capabilities: CapabilityDetail[]
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface DeviceModelVariant {
|
|
238
|
+
device_model_variant_id: string
|
|
239
|
+
color_name: string | null
|
|
240
|
+
style_name: string | null
|
|
241
|
+
primary_color_hex: string | null
|
|
242
|
+
manufacturer_model_id: string | null
|
|
243
|
+
asin: string | null
|
|
244
|
+
gtins: unknown
|
|
245
|
+
marketplace_listings: unknown
|
|
246
|
+
sort_order: number
|
|
247
|
+
images: DeviceAsset[]
|
|
248
|
+
created_at: string
|
|
249
|
+
updated_at: string
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export interface DeviceModel {
|
|
253
|
+
device_model_id: string
|
|
254
|
+
slug: string
|
|
255
|
+
display_name: string | null
|
|
256
|
+
description_md: string | null
|
|
257
|
+
product_url: string | null
|
|
258
|
+
is_forbidden_to_3dparty: boolean | null
|
|
259
|
+
no_longer_sold: boolean | null
|
|
260
|
+
shop_listings: unknown
|
|
261
|
+
last_commerce_search_at: string | null
|
|
262
|
+
manufacturer: ManufacturerRef | null
|
|
263
|
+
device_type: DeviceTypeRef | null
|
|
264
|
+
device_type_properties: unknown
|
|
265
|
+
variants: DeviceModelVariant[]
|
|
266
|
+
featured_image: DeviceAsset | null
|
|
267
|
+
providers: ProviderRef[]
|
|
268
|
+
capabilities_by_provider: ProviderCapabilities[]
|
|
269
|
+
capabilities_stale: boolean
|
|
270
|
+
created_at: string
|
|
271
|
+
updated_at: string
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Device model summaries (`device_models/summaries/list`, DEVDB-437):
|
|
275
|
+
// the same models in a slim shape, without storage internals or commerce data.
|
|
276
|
+
|
|
277
|
+
export interface DeviceImageFormat {
|
|
278
|
+
url: string
|
|
279
|
+
width: number | null
|
|
280
|
+
height: number | null
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export interface DeviceImage {
|
|
284
|
+
url: string
|
|
285
|
+
mime: string | null
|
|
286
|
+
width: number | null
|
|
287
|
+
height: number | null
|
|
288
|
+
formats: Partial<Record<MediaFormatName, DeviceImageFormat>>
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export interface CapabilitySummary {
|
|
292
|
+
name: CapabilityName
|
|
293
|
+
supported: CapabilitySupported
|
|
294
|
+
integration_support_level: IntegrationSupportLevel | null
|
|
295
|
+
report: CapabilityReport | null
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export interface DeviceModelSummaryVariant {
|
|
299
|
+
device_model_variant_id: string
|
|
300
|
+
color_name: string | null
|
|
301
|
+
style_name: string | null
|
|
302
|
+
primary_color_hex: string | null
|
|
303
|
+
manufacturer_model_id: string | null
|
|
304
|
+
images: DeviceImage[]
|
|
305
|
+
/** Only with `include=commerce`. */
|
|
306
|
+
asin?: string | null
|
|
307
|
+
/** Only with `include=commerce`. */
|
|
308
|
+
gtins?: unknown
|
|
309
|
+
/** Only with `include=commerce`. */
|
|
310
|
+
marketplace_listings?: unknown
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export interface DeviceModelSummary {
|
|
314
|
+
device_model_id: string
|
|
315
|
+
slug: string
|
|
316
|
+
display_name: string | null
|
|
317
|
+
description_md: string | null
|
|
318
|
+
product_url: string | null
|
|
319
|
+
no_longer_sold: boolean | null
|
|
320
|
+
is_forbidden_to_3dparty: boolean | null
|
|
321
|
+
manufacturer: ManufacturerRef | null
|
|
322
|
+
device_type: DeviceTypeRef | null
|
|
323
|
+
device_type_properties: unknown
|
|
324
|
+
featured_image: DeviceImage | null
|
|
325
|
+
variants: DeviceModelSummaryVariant[]
|
|
326
|
+
providers: ProviderRef[]
|
|
327
|
+
capabilities_by_provider: Array<{
|
|
328
|
+
provider: ProviderRef
|
|
329
|
+
capabilities: CapabilitySummary[]
|
|
330
|
+
}>
|
|
331
|
+
capabilities_stale: boolean
|
|
332
|
+
/** Only with `include=commerce`. */
|
|
333
|
+
shop_listings?: unknown
|
|
334
|
+
/** Only with `include=commerce`. */
|
|
335
|
+
last_commerce_search_at?: string | null
|
|
336
|
+
updated_at: string
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export interface ManufacturerDefaultDeviceImage {
|
|
340
|
+
device_type: DeviceTypeRef
|
|
341
|
+
asset: DeviceAsset
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export interface Manufacturer {
|
|
345
|
+
manufacturer_id: string
|
|
346
|
+
slug: string
|
|
347
|
+
display_name: string | null
|
|
348
|
+
website: string | null
|
|
349
|
+
headquarters: string | null
|
|
350
|
+
country_of_origin: string | null
|
|
351
|
+
parent_org: string | null
|
|
352
|
+
inc_date: string | null
|
|
353
|
+
customer_support_phone: string | null
|
|
354
|
+
customer_support_email: string | null
|
|
355
|
+
customer_support_url: string | null
|
|
356
|
+
description_md: string | null
|
|
357
|
+
seam_api_guide: string | null
|
|
358
|
+
commerce_footprint: unknown
|
|
359
|
+
last_commerce_search_at: string | null
|
|
360
|
+
logos: DeviceAsset[]
|
|
361
|
+
default_device_images: ManufacturerDefaultDeviceImage[]
|
|
362
|
+
providers: ProviderRef[]
|
|
363
|
+
device_model_count: number
|
|
364
|
+
created_at: string
|
|
365
|
+
updated_at: string
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export interface Pagination {
|
|
369
|
+
has_next_page: boolean
|
|
370
|
+
next_page_cursor: string | null
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Responses
|
|
374
|
+
|
|
375
|
+
export interface CompatibilityResponse {
|
|
376
|
+
partners: CompatiblePartner[]
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export interface DeviceModelsListResponse {
|
|
380
|
+
device_models: DeviceModel[]
|
|
381
|
+
pagination: Pagination
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export interface DeviceModelSummariesListResponse {
|
|
385
|
+
device_models: DeviceModelSummary[]
|
|
386
|
+
pagination: Pagination
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export interface ManufacturersListResponse {
|
|
390
|
+
manufacturers: Manufacturer[]
|
|
391
|
+
pagination: Pagination
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export interface EcosystemErrorResponse {
|
|
395
|
+
ok: false
|
|
396
|
+
error: {
|
|
397
|
+
type: string
|
|
398
|
+
message: string
|
|
399
|
+
data?: Record<string, unknown>
|
|
400
|
+
request_id?: string
|
|
401
|
+
}
|
|
402
|
+
}
|