import { s } from "../registry/schema.js"; /** The same as a schema. The friendly names are checked with the instance, by the rules of the interface. */ export const commonOptions = s.object({ instance: s.optional(s.string()), friendlyNames: s.optional(s.array(s.unknown())), retrievable: s.optional(s.boolean()), proactivelyReported: s.optional(s.boolean()), nonControllable: s.optional(s.boolean()), }); /** One interface as an endpoint declares it: the descriptor, and what the declaration says about this endpoint. */ export class Capability { constructor(descriptor, declared) { this.descriptor = descriptor; /** The endpoint the capability is declared on; the device sets it. */ this.endpointId = ""; /** What the bridge logs about the declaration, once, when it answers a discovery. */ this.notes = []; this.instance = declared.instance ?? ""; this.friendlyNames = declared.friendlyNames ?? []; this.retrievable = declared.retrievable ?? true; this.proactivelyReported = declared.proactivelyReported ?? false; this.nonControllable = declared.nonControllable; this.options = declared.options; } get namespace() { return this.descriptor.namespace; } /** Mappings of "open", "close", "raise", "lower" and of states, when the declaration has any. */ get semantics() { const { semantics } = this.options; const mapped = (semantics?.actionMappings?.length ?? 0) + (semantics?.stateMappings?.length ?? 0); return mapped > 0 ? semantics : undefined; } /** The capability object for discovery, its fields in the order of the example on alexa-discovery-objects.html. */ toJSON() { const { descriptor, semantics } = this; const extras = descriptor.discovery ? descriptor.discovery(this) : {}; const json = { type: "AlexaInterface", interface: descriptor.namespace, ...(this.instance ? { instance: this.instance } : {}), version: descriptor.version, }; if (extras.properties !== false) { json.properties = { supported: Object.keys(descriptor.properties).map((name) => ({ name })), proactivelyReported: this.proactivelyReported, retrievable: this.retrievable, }; if (this.nonControllable !== undefined) json.properties.nonControllable = this.nonControllable; } if (this.friendlyNames.length > 0) json.capabilityResources = { friendlyNames: this.friendlyNames }; if (extras.configuration) json.configuration = extras.configuration; if (extras.configurations) json.configurations = extras.configurations; if (semantics) json.semantics = semantics; return { ...json, ...extras.topLevel }; } }