import {z} from 'zod' export type CapabilityConfigurationValue = {key: string, range?: Array | undefined, enabledValues?: Array | undefined, step?: number | undefined}; export type CapabilityConfiguration = {values: Array}; export type Restriction = {tier: number, historyRetentionTTLDays?: number | undefined, visibleWhenRestricted?: boolean | undefined}; export type CapabilityReferenceRequest = {id: string, version?: number | undefined, optional?: boolean | undefined, config?: CapabilityConfiguration | undefined, restrictions?: Restriction | undefined}; export type DeviceCategory = {name: string, categoryType: 'manufacturer' | 'user'}; export type DeviceComponentRequest = {label?: string | undefined, id: unknown, capabilities: Array, categories: Array, restrictions?: Restriction | undefined, optional?: boolean | undefined}; export type PreferenceType = 'integer' | 'number' | 'boolean' | 'string' | 'enumeration'; export type PreferenceRequest = {preferenceId?: string | undefined, name: string, title: string, description?: string | undefined, explicit?: boolean | undefined, required?: boolean | undefined, preferenceType: PreferenceType, definition: {minimum?: number | undefined, maximum?: number | undefined, minLength?: number | undefined, maxLength?: number | undefined, default: unknown, stringType?: ('text' | 'password' | 'paragraph') | undefined, options?: {[key: string]: string} | undefined}}; export type DeviceProfileMetadata = unknown; export type IconUrl = string; export type Value = string; export type ValueType = string; export type Operator = 'CONTAINS' | 'DOES_NOT_CONTAIN' | 'EQUALS' | 'DOES_NOT_EQUAL' | 'GREATER_THAN' | 'GREATER_THAN_OR_EQUALS' | 'LESS_THAN' | 'LESS_THAN_OR_EQUALS' | 'ONE_OF'; export type Component = string; export type Version = number; export type VisibleCondition = {value: Value, valueType?: ValueType | undefined, operator: Operator, operand: string, component: Component, capability: string, version?: Version | undefined}; export type Icons = Array<{group?: string | undefined, iconUrl?: IconUrl | undefined, runningConditions?: Array | undefined, badge?: (Array<{iconUrl: IconUrl, visibleConditions?: Array | undefined}>) | undefined, productKeys?: Array<{mnId: string, setupId: string}> | undefined}>; export type DpInfo = Array<{os: 'android' | 'ios' | 'tizen' | 'web', dpUri: string, serverDpUri?: string | undefined, operatingMode?: string | undefined, arguments?: Array<{key: string, value: string}> | undefined}>; export type StPluginApiVersion = string; export type DpInfos = Array<{stPluginApiVersion?: StPluginApiVersion | undefined, dpInfo: DpInfo}>; export type PresentationDescription = string; export type Idx = number; export type Group = string; export type AlternativeItem = {key: string, value: string, type?: ('inactive' | 'active') | undefined, iconUrl?: IconUrl | undefined, description?: string | undefined}; export type Alternatives = Array; export type CapabilityValueForDashboardState = {label?: string | undefined, alternatives?: Alternatives | undefined}; export type Composite = boolean; export type TimeFormat = string; export type FormatInfo = Array<{key: Value, type: 'remainingTime' | 'time', remainingTime?: ({timeFormat: TimeFormat, frequency?: number | undefined}) | undefined, time?: {timeFormat: TimeFormat} | undefined}>; export type VisibleConditionForDashboardState = {value: Value, valueType?: ValueType | undefined, operator: Operator, operand: string, component: Component, capability: string, version?: Version | undefined, isOffline?: boolean | undefined}; export type DeviceConfigEntryForDashboardState = {component: string, capability: string, version?: Version | undefined, idx?: Idx | undefined, group?: Group | undefined, values?: Array | undefined, composite?: Composite | undefined, formatInfo?: FormatInfo | undefined, visibleCondition?: VisibleConditionForDashboardState | undefined}; export type ArgumentType = string; export type PushButton = {command: string, argument?: string | undefined, argumentType?: ArgumentType | undefined}; export type ToggleSwitchForDashboard = {command: {name?: string | undefined, on: string, off: string, argumentType?: ArgumentType | undefined}, state?: ({value?: Value | undefined, on: string, off: string, valueType?: ValueType | undefined, alternatives?: Alternatives | undefined}) | undefined}; export type SwitchForDashboard = {command: {name?: string | undefined, on: string, off: string, argumentType?: ArgumentType | undefined}, state?: ({value?: Value | undefined, on: string, off: string, valueType?: ValueType | undefined, alternatives?: Alternatives | undefined}) | undefined}; export type FormattedLabel = string; export type StandbyPowerSwitchForDashboard = {command: {name?: string | undefined, on: string, off: string, argumentType?: ArgumentType | undefined}, state?: ({value: Value, valueType?: ValueType | undefined, on: string, off: string, label?: FormattedLabel | undefined, alternatives?: Alternatives | undefined}) | undefined}; export type StatelessPowerToggleForDashboard = {command: string, argument?: string | undefined, argumentType?: ArgumentType | undefined}; export type PlayPause = {command: {name?: string | undefined, play: string, pause: string, argumentType?: ArgumentType | undefined}, state: {value: Value, valueType?: ValueType | undefined, play: string, pause: string, alternatives?: Alternatives | undefined}}; export type PlayStop = {command: {name?: string | undefined, play: string, stop: string, argumentType?: ArgumentType | undefined}, state: {value: Value, play: string, stop: string, alternatives?: Alternatives | undefined, valueType?: ValueType | undefined}}; export type DeviceConfigEntryForDashboardAction = {component: string, capability: string, version?: Version | undefined, idx?: Idx | undefined, group?: Group | undefined, inline?: ({displayType: 'pushButton' | 'toggleSwitch' | 'switch' | 'standbyPowerSwitch' | 'statelessPowerToggle' | 'playPause' | 'playStop', pushButton?: PushButton | undefined, toggleSwitch?: ToggleSwitchForDashboard | undefined, switch?: SwitchForDashboard | undefined, standbyPowerSwitch?: StandbyPowerSwitchForDashboard | undefined, statelessPowerToggle?: StatelessPowerToggleForDashboard | undefined, playPause?: PlayPause | undefined, playStop?: PlayStop | undefined, group?: Group | undefined}) | undefined, visibleCondition?: VisibleCondition | undefined}; export type BasicPlusCamera = {image: {capability: string, version?: Version | undefined, component: Component, value: Value}, overlayIcons?: (Array<{iconUrl: string, visibleCondition?: VisibleCondition | undefined}>) | undefined}; export type Step = number; export type Range = Array; export type SupportedValuesForNumericConstraints = string; export type ButtonForTv = {capability: string, version?: Version | undefined, component: Component, command: string, argument?: string | undefined, iconUrl?: string | undefined}; export type OperatorForVisibleConditions = 'AND' | 'OR'; export type HideDashboardActions = boolean; export type BasicPlusTv = {volume?: ({capability: string, version?: Version | undefined, component: Component, label?: string | undefined, command: {name?: string | undefined, increase?: string | undefined, decrease?: string | undefined}, value?: Value | undefined, step?: Step | undefined, range?: Range | undefined, supportedValues?: SupportedValuesForNumericConstraints | undefined}) | undefined, buttons: Array, channel?: ({capability: string, version?: Version | undefined, component: Component, label?: string | undefined, value?: Value | undefined, command: {name?: string | undefined, increase?: string | undefined, decrease?: string | undefined}}) | undefined, directionalPad?: ({capability: string, version?: Version | undefined, component: Component, command: {name?: string | undefined, up: string, down: string, left: string, right: string, ok: string}}) | undefined, operator?: OperatorForVisibleConditions | undefined, visibleConditions?: Array | undefined, hideDashboardActions?: HideDashboardActions | undefined}; export type Unit = string; export type SliderForLight = {component: string, capability: string, version?: Version | undefined, range: Range, step?: Step | undefined, unit?: Unit | undefined, supportedValues?: SupportedValuesForNumericConstraints | undefined, command: string, value: Value, valueType?: ValueType | undefined, argumentType?: ArgumentType | undefined, label: string}; export type BasicPlusLight = {dimmer: SliderForLight, colorTemperature?: SliderForLight | undefined, colorControl?: ({component: string, capability: string, version?: Version | undefined, command: string, value?: Value | undefined, color: {hue?: Value | undefined, saturation?: Value | undefined}}) | undefined, hideDashboardActions?: HideDashboardActions | undefined}; export type BasicPlusActions = Array<{command: string, argument?: string | undefined, argumentType?: ArgumentType | undefined, iconUrl?: string | undefined, component: string, capability: string, version?: Version | undefined, operator?: OperatorForVisibleConditions | undefined, visibleConditions?: Array | undefined}>; export type VisibleConditionForColorItem = {referTo?: ({component: Component, capability: string, version?: Version | undefined, value: Value, valueType?: ValueType | undefined}) | undefined, operator: Operator, operand: string}; export type BasicPlusStateBoardColors = {color: string, operator?: OperatorForVisibleConditions | undefined, visibleConditions?: Array | undefined}; export type BasicPlusStateBoardItem = {capability: string, version?: Version | undefined, component: string, value: Value, valueType?: ValueType | undefined, label: string, unit?: Unit | undefined, alternatives?: Alternatives | undefined, iconUrl?: string | undefined, colors?: Array | undefined, operator?: OperatorForVisibleConditions | undefined, visibleConditions?: Array | undefined}; export type BasicPlusStateBoard = Array; export type BasicPlusProgressBarsStateItem = {label: FormattedLabel, alternatives?: Alternatives | undefined, capability: string, version?: Version | undefined, component: Component, formatInfo?: FormatInfo | undefined, iconUrl?: string | undefined, placement?: ('START' | 'END') | undefined}; export type BasicPlusProgressBarsBarItem = {capability: string, version?: Version | undefined, component: string, value: Value, valueType?: ValueType | undefined, range?: Array | undefined}; export type BasicPlusProgressBars = Array<{headers?: Array | undefined, bar?: BasicPlusProgressBarsBarItem | undefined, footers?: Array | undefined, operator?: OperatorForVisibleConditions | undefined, visibleConditions?: Array | undefined}>; export type SizeForPanelItem = '1x1' | '2x1' | '3x1' | '4x1' | '1/3x1' | '1x2' | '2x2' | '4x2'; export type CapabilityValueForPanel = {enabledValues?: Array | undefined, label?: string | undefined, alternatives?: Alternatives | undefined, range?: Range | undefined, step?: Step | undefined, key?: string | undefined}; export type StepperWithAvailableSize = {command: {name?: string | undefined, increase?: string | undefined, decrease?: string | undefined, argumentType?: ArgumentType | undefined}, step: Step, range: Range, supportedValues?: SupportedValuesForNumericConstraints | undefined, state: {value: Value, unit?: Unit | undefined, valueType?: ValueType | undefined, label?: string | undefined, alternatives?: Alternatives | undefined}, availableSizes?: (Array<'2x1' | '3x1' | '4x1' | '1x2' | '2x2'>) | undefined}; export type SupportedValues = string; export type ListWithAvailableSize = {command: {name?: string | undefined, description?: string | undefined, alternatives: Alternatives, argumentType?: ArgumentType | undefined, supportedValues?: SupportedValues | undefined}, state?: ({value: Value, valueType?: ValueType | undefined, alternatives: Alternatives}) | undefined, availableSizes?: (Array<'2x1' | '3x1' | '4x1' | '1/3x1' | '2x2'>) | undefined}; export type PushButtonWithAvailableSize = {command: string, argument?: string | undefined, argumentType?: ArgumentType | undefined, iconUrl?: string | undefined, availableSizes?: (Array<'1x1' | '2x1' | '3x1' | '4x1' | '1/3x1' | '2x2'>) | undefined}; export type ArgumentName = string; export type ListForInvokeButtonArgument = {alternatives: Alternatives, supportedValues?: SupportedValues | undefined, label: string}; export type StateInvokeButtonArgument = {label: string, alternatives?: Alternatives | undefined}; export type ArgumentsForInvokeButton = {name: ArgumentName, value: string, argumentType?: ArgumentType | undefined, displayType?: ('list' | 'state') | undefined, list?: ListForInvokeButtonArgument | undefined, state?: StateInvokeButtonArgument | undefined}; export type CommandsForInvokeButton = {state: string, label?: string | undefined, iconUrl?: string | undefined, command: {name: string, argument?: string | undefined, argumentType?: ArgumentType | undefined, confirmation?: ({label: string, title?: string | undefined, description?: string | undefined}) | undefined, arguments?: Array | undefined, supportedValues?: string | undefined}}; export type InvokeButtonWithAvailableSize = {value: string, valueType?: ValueType | undefined, refreshInterval?: number | undefined, commands: Array, availableSizes?: (Array<'1x1' | '2x1' | '3x1' | '4x1' | '1/3x1' | '2x2'>) | undefined}; export type StateWithAvailableSize = {label: FormattedLabel, unit?: Unit | undefined, alternatives?: Alternatives | undefined, availableSizes?: Array<'2x1'> | undefined}; export type SliderWithAvailableSize = {range: Range, step?: Step | undefined, unit?: Unit | undefined, supportedValues?: SupportedValuesForNumericConstraints | undefined, alternatives?: Alternatives | undefined, command: string, argumentType?: ArgumentType | undefined, value?: Value | undefined, valueType?: ValueType | undefined, availableSizes?: (Array<'4x1' | '4x2'>) | undefined}; export type EmptyWithAvailableSize = {availableSizes?: (Array<'1x1' | '2x1' | '3x1' | '4x1' | '1/3x1' | '1x2' | '2x2'>) | undefined}; export type HideOnUnmatchForVisibleCondition = boolean; export type PanelForDeviceConfig = {items: Array<{component: string, capability: string, version?: Version | undefined, idx?: number | undefined, size: SizeForPanelItem, values?: Array | undefined, inline?: ({label?: string | undefined, displayType: 'stepper' | 'list' | 'pushButton' | 'invokeButton' | 'state' | 'slider' | 'empty', stepper?: StepperWithAvailableSize | undefined, list?: ListWithAvailableSize | undefined, pushButton?: PushButtonWithAvailableSize | undefined, invokeButton?: InvokeButtonWithAvailableSize | undefined, state?: StateWithAvailableSize | undefined, slider?: SliderWithAvailableSize | undefined, empty?: EmptyWithAvailableSize | undefined}) | undefined, operator?: OperatorForVisibleConditions | undefined, visibleConditions?: Array | undefined, hideOnUnmatch?: HideOnUnmatchForVisibleCondition | undefined}>, operator?: OperatorForVisibleConditions | undefined, visibleConditions?: Array | undefined, hideDashboardActions?: HideDashboardActions | undefined}; export type BasicPlusItem = {displayType: 'camera' | 'tv' | 'light' | 'panel' | 'actions' | 'stateBoard' | 'progressBars', camera?: BasicPlusCamera | undefined, tv?: BasicPlusTv | undefined, light?: BasicPlusLight | undefined, actions?: BasicPlusActions | undefined, stateBoard?: BasicPlusStateBoard | undefined, progressBars?: BasicPlusProgressBars | undefined, panel?: PanelForDeviceConfig | undefined}; export type GroupVisibleConditions = {value: Value, valueType?: ValueType | undefined, operator: Operator, operand: string, component: Component, capability: string, version?: Version | undefined}; export type CapabilityValue = {enabledValues?: Array | undefined, label?: string | undefined, alternatives?: Alternatives | undefined, range?: Range | undefined, step?: Step | undefined, key: string}; export type PatchItem = {op: 'add' | 'replace' | 'remove', path: string, value?: Record | undefined}; export type DeviceConfigEntry = {component: string, capability: string, version?: Version | undefined, values?: Array | undefined, patch?: Array | undefined, visibleCondition?: VisibleCondition | undefined}; export type ExcludeItemsAttributes = Array<{name: string, excludedValues?: Array | undefined}>; export type ExcludedConditionItemId = {id?: number | undefined, value?: Record | undefined, exclude: Array<{component?: string | undefined, capability: string, version?: number | undefined, attributes?: ExcludeItemsAttributes | undefined}>}; export type ExcludedDeviceConditionConfigEntry = {component: string, capability: string, version?: Version | undefined, values?: Array | undefined, patch?: Array | undefined, visibleCondition?: VisibleCondition | undefined, exclusion?: Array | undefined}; export type ExcludeItemsCommands = Array<{name: string, excludedValues?: Array | undefined}>; export type ExcludedActionItemId = {id?: number | undefined, value?: Record | undefined, exclude: Array<{component?: string | undefined, capability: string, version?: number | undefined, commands?: ExcludeItemsCommands | undefined}>}; export type ExcludedDeviceActionConfigEntry = {component: string, capability: string, version?: Version | undefined, values?: Array | undefined, patch?: Array | undefined, visibleCondition?: VisibleCondition | undefined, exclusion?: Array | undefined}; export type DescriptionItem = {operator?: OperatorForVisibleConditions | undefined, label: string, visibleConditions?: Array | undefined}; export type DescriptionsInAutomation = {conditions?: Array | undefined, actions?: Array | undefined}; export type EmbeddedDeviceConfiguration = {icons?: Icons | undefined, dpInfo?: DpInfo | undefined, dpInfos?: DpInfos | undefined, description?: PresentationDescription | undefined, dashboard?: ({states?: Array | undefined, actions?: Array | undefined, basicPlus?: Array | undefined, groupVisibleConditions?: GroupVisibleConditions | undefined}) | undefined, detailView?: Array | undefined, automation?: ({conditions?: Array | undefined, actions?: Array | undefined, descriptions?: DescriptionsInAutomation | undefined}) | undefined}; export type CreateDeviceProfileRequest = {name: unknown, components: Array, preferences?: Array | undefined, metadata?: DeviceProfileMetadata | undefined, deviceConfig?: EmbeddedDeviceConfiguration | undefined, presentationId?: string | undefined}; export type CreateApiDeviceprofilesArgs = {Authorization: unknown, 'X-ST-Organization'?: unknown | undefined, body: CreateDeviceProfileRequest}; export type CreateApiDeviceprofilesOptions = {baseUrl?: string | undefined, Bearer?: string | undefined, fetch?: typeof fetch | undefined}; export const deviceProfileMetadata = z.unknown(); export const deviceRestriction = z.object({tier: z.number().int(), historyRetentionTTLDays: z.number().int().optional(), visibleWhenRestricted: z.boolean().optional()}); export const deviceProfileStatus = z.enum(["DEVELOPMENT", "PUBLISHED"]); export const preferenceType = z.enum(["integer", "number", "boolean", "string", "enumeration"]); export const preferenceResponse = z.object({preferenceId: z.string().optional(), name: z.string().optional(), title: z.string(), description: z.string().optional(), required: z.boolean().optional(), explicit: z.boolean().optional(), preferenceType: preferenceType}); export const capabilityConfigurationValue = z.object({key: z.string(), range: z.array(z.number()).optional(), enabledValues: z.array(z.string()).optional(), step: z.number().optional()}); export const capabilityConfiguration = z.object({values: z.array(capabilityConfigurationValue)}); export const restriction = z.object({tier: z.number().int(), historyRetentionTTLDays: z.number().int().optional(), visibleWhenRestricted: z.boolean().optional()}); export const attributeState = z.object({value: z.object({}).optional(), unit: z.string().optional(), data: z.record(z.string(), z.object({})).optional(), timestamp: z.string().optional()}); export const capabilityStatus = z.record(z.string(), attributeState); export const deviceCapabilityReference = z.object({id: z.string(), version: z.number().int().optional(), optional: z.boolean().optional(), config: capabilityConfiguration.optional(), restrictions: restriction.optional(), ephemeral: z.boolean().optional(), status: capabilityStatus.optional()}); export const deviceCategory = z.object({name: z.string(), categoryType: z.enum(["manufacturer", "user"])}); export const deviceComponent = z.object({id: z.string(), label: z.string().optional(), capabilities: z.array(deviceCapabilityReference), categories: z.array(deviceCategory), restrictions: restriction.optional(), optional: z.boolean().optional()}); export const deviceProfileResponse = z.object({id: z.string(), name: z.string(), metadata: deviceProfileMetadata.optional(), restrictions: deviceRestriction.optional(), presentationId: z.string().optional(), migrationStatus: z.enum(["MIGRATED", "NOT_MIGRATED"]), status: deviceProfileStatus, preferences: z.array(preferenceResponse).optional(), components: z.array(deviceComponent)}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Create a Device Profile * * POST /deviceprofiles */ export const createApiDeviceprofiles = async (args: CreateApiDeviceprofilesArgs, options?: CreateApiDeviceprofilesOptions) => { const {baseUrl = "https://api.smartthings.com/v1", fetch: fetchFn = fetch, Bearer} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (args.Authorization != null) headers.set("Authorization", String(args.Authorization)) if (args['X-ST-Organization'] != null) headers.set("X-ST-Organization", String(args['X-ST-Organization'])) if (Bearer !== undefined) headers.set('authorization', `Bearer ${Bearer}`) const url = `${baseUrl.replace(/\/+$/, '')}/deviceprofiles${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(deviceProfileResponse, await res.json()) };