registry: describe an Alexa interface as data
src/registry/ holds what the library knows about an interface: namespace, version, the page it was read from, properties with their value schemas and directives with their payload schemas. Five interfaces are described (Alexa, PowerController, BrightnessController, TemperatureSensor, EndpointHealth); the other 65 names of AlexaInterfaceType are stubs with the version and property names of 1.5.2. schema.ts is the run-time check behind it (241 lines, no new dependency), catalog.ts the vocabularies of the pages: 103 assets (23 units), 6 actions, 9 states, 56 display categories, 22 reserved words, 73 error types under 11 namespaces. AlexaInterface.getVersion() and getProps() read the registry; the two switch statements are gone (-167 lines). On the wire: Alexa.EndpointHealth is announced at 3.1 (was 3.3; the page is titled 3.1 and no page mentions 3.3), and TimeHoldController and Camera.LiveViewController at 3 and 1.7 (1.5.2 sent the string "UNKNOWN"). DisplayCategory gains VACUUM. New exports: registry, DeclarationError, SchemaError, Assets, Units, Actions, States, DisplayCategories and the descriptor types. Tests: 20 JSON examples of the five pages under test/fixtures/alexa-docs; every directive payload and property value in them parses with its descriptor. npm test: 57 pass (was 30) in 10.8 s, also on Node 18.20.8 and 20.20.2. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
128ca35c2a
commit
aa0ffd64ea
93 changed files with 4058 additions and 490 deletions
23
dist/cjs/registry/interfaces/Alexa.js
vendored
Normal file
23
dist/cjs/registry/interfaces/Alexa.js
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Alexa = void 0;
|
||||
const schema_js_1 = require("../schema.js");
|
||||
const types_js_1 = require("../types.js");
|
||||
/**
|
||||
* The base interface: every endpoint lists it (alexa-interface.html, "Support the Alexa interface in all add-ons").
|
||||
* Its one directive to a device is ReportState, answered with a StateReport.
|
||||
*/
|
||||
exports.Alexa = (0, types_js_1.defineInterface)({
|
||||
namespace: "Alexa",
|
||||
version: "3",
|
||||
doc: "https://developer.amazon.com/docs/alexaplus/device-apis/alexa-interface.html",
|
||||
kind: "base",
|
||||
tier: 1,
|
||||
instanced: false,
|
||||
properties: {},
|
||||
directives: {
|
||||
ReportState: { name: "ReportState", payload: schema_js_1.s.object({}) },
|
||||
},
|
||||
// { type, interface, version } and nothing else, as in the discovery example of the page
|
||||
discovery: () => ({ properties: false }),
|
||||
});
|
||||
27
dist/cjs/registry/interfaces/BrightnessController.js
vendored
Normal file
27
dist/cjs/registry/interfaces/BrightnessController.js
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.BrightnessController = void 0;
|
||||
const schema_js_1 = require("../schema.js");
|
||||
const types_js_1 = require("../types.js");
|
||||
/** Both directives turn a light that is off on, at the brightness asked for (alexa-brightnesscontroller.html). */
|
||||
exports.BrightnessController = (0, types_js_1.defineInterface)({
|
||||
namespace: "Alexa.BrightnessController",
|
||||
version: "3",
|
||||
doc: "https://developer.amazon.com/docs/alexaplus/device-apis/alexa-brightnesscontroller.html",
|
||||
kind: "controller",
|
||||
tier: 1,
|
||||
instanced: false,
|
||||
properties: {
|
||||
brightness: { name: "brightness", value: schema_js_1.s.number({ min: 0, max: 100, integer: true }) },
|
||||
},
|
||||
directives: {
|
||||
SetBrightness: {
|
||||
name: "SetBrightness",
|
||||
payload: schema_js_1.s.object({ brightness: schema_js_1.s.number({ min: 0, max: 100, integer: true }) }),
|
||||
},
|
||||
AdjustBrightness: {
|
||||
name: "AdjustBrightness",
|
||||
payload: schema_js_1.s.object({ brightnessDelta: schema_js_1.s.number({ min: -100, max: 100, integer: true }) }),
|
||||
},
|
||||
},
|
||||
});
|
||||
32
dist/cjs/registry/interfaces/EndpointHealth.js
vendored
Normal file
32
dist/cjs/registry/interfaces/EndpointHealth.js
vendored
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.EndpointHealth = exports.CONNECTIVITY_REASONS = void 0;
|
||||
const schema_js_1 = require("../schema.js");
|
||||
const types_js_1 = require("../types.js");
|
||||
exports.CONNECTIVITY_REASONS = [
|
||||
"WIFI_BAD_PASSWORD", "WIFI_AP_NOT_FOUND", "WIFI_ROUTER_UNREACHABLE", "WIFI_AP_CHANNEL_QUALITY_LOW",
|
||||
"INTERNET_UNREACHABLE", "CAPTIVE_PORTAL_CHECK_FAILED", "UNKNOWN",
|
||||
];
|
||||
/**
|
||||
* Version 3.1, as the page is titled. It defines connectivity only. Examples on other pages declare 3 and 3.2;
|
||||
* alex2node 1.x declared 3.3, which no page mentions.
|
||||
*/
|
||||
exports.EndpointHealth = (0, types_js_1.defineInterface)({
|
||||
namespace: "Alexa.EndpointHealth",
|
||||
version: "3.1",
|
||||
doc: "https://developer.amazon.com/docs/alexaplus/device-apis/alexa-endpointhealth.html",
|
||||
kind: "sensor",
|
||||
tier: 1,
|
||||
instanced: false,
|
||||
properties: {
|
||||
connectivity: {
|
||||
name: "connectivity",
|
||||
value: schema_js_1.s.object({
|
||||
value: schema_js_1.s.enum("OK", "UNREACHABLE"),
|
||||
reason: schema_js_1.s.optional(schema_js_1.s.enum(...exports.CONNECTIVITY_REASONS)),
|
||||
}),
|
||||
note: "in every Response, StateReport and ChangeReport; a change of it reported within three seconds",
|
||||
},
|
||||
},
|
||||
directives: {},
|
||||
});
|
||||
31
dist/cjs/registry/interfaces/PowerController.js
vendored
Normal file
31
dist/cjs/registry/interfaces/PowerController.js
vendored
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.PowerController = void 0;
|
||||
const schema_js_1 = require("../schema.js");
|
||||
const types_js_1 = require("../types.js");
|
||||
exports.PowerController = (0, types_js_1.defineInterface)({
|
||||
namespace: "Alexa.PowerController",
|
||||
version: "3",
|
||||
doc: "https://developer.amazon.com/docs/alexaplus/device-apis/alexa-powercontroller.html",
|
||||
kind: "controller",
|
||||
tier: 1,
|
||||
instanced: false,
|
||||
properties: {
|
||||
powerState: { name: "powerState", value: schema_js_1.s.enum("ON", "OFF") },
|
||||
},
|
||||
directives: {
|
||||
TurnOn: { name: "TurnOn", payload: schema_js_1.s.object({}) },
|
||||
TurnOff: { name: "TurnOff", payload: schema_js_1.s.object({}) },
|
||||
},
|
||||
options: schema_js_1.s.object({
|
||||
// The directives Alexa asks the user to confirm before it sends them. Amazon supports this for devices in Japan
|
||||
// only (alexa-discovery-objects.html, "VerificationsRequired object").
|
||||
verificationsRequired: schema_js_1.s.optional(schema_js_1.s.array(schema_js_1.s.enum("TurnOn", "TurnOff"), { min: 1 })),
|
||||
}, { unknownKeys: "reject" }),
|
||||
discovery({ options }) {
|
||||
if (!options.verificationsRequired)
|
||||
return {};
|
||||
const confirmed = options.verificationsRequired.map((directive) => ({ directive, methods: [{ "@type": "Confirmation" }] }));
|
||||
return { topLevel: { verificationsRequired: confirmed } };
|
||||
},
|
||||
});
|
||||
18
dist/cjs/registry/interfaces/TemperatureSensor.js
vendored
Normal file
18
dist/cjs/registry/interfaces/TemperatureSensor.js
vendored
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TemperatureSensor = void 0;
|
||||
const schema_js_1 = require("../schema.js");
|
||||
const types_js_1 = require("../types.js");
|
||||
/** A sensor: an endpoint that has it declares Alexa.EndpointHealth as well (alexa-temperaturesensor.html). */
|
||||
exports.TemperatureSensor = (0, types_js_1.defineInterface)({
|
||||
namespace: "Alexa.TemperatureSensor",
|
||||
version: "3",
|
||||
doc: "https://developer.amazon.com/docs/alexaplus/device-apis/alexa-temperaturesensor.html",
|
||||
kind: "sensor",
|
||||
tier: 1,
|
||||
instanced: false,
|
||||
properties: {
|
||||
temperature: { name: "temperature", value: schema_js_1.s.temperature() },
|
||||
},
|
||||
directives: {},
|
||||
});
|
||||
102
dist/cjs/registry/interfaces/stubs.js
vendored
Normal file
102
dist/cjs/registry/interfaces/stubs.js
vendored
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.STUBS = void 0;
|
||||
// Interfaces without a descriptor of their own. A stub names the interface with the version and the properties
|
||||
// alex2node 1.5.2 put in discovery, so an endpoint that declares one is announced as before. Nothing about it is
|
||||
// checked, and the version is the one 1.5.2 sent, which is not always the one on the page of the interface
|
||||
// (Alexa.Speaker is "3" there). A row leaves this table when a descriptor is written from that page.
|
||||
const schema_js_1 = require("../schema.js");
|
||||
const DEVICE_APIS = "https://developer.amazon.com/docs/alexaplus/device-apis";
|
||||
const LIST_OF_INTERFACES = `${DEVICE_APIS}/list-of-interfaces.html`;
|
||||
// "As of August 7, 2026, Automotive skills and the associated Alexa.AuthorizationController and
|
||||
// Alexa.Automotive.VehicleData APIs are no longer available."
|
||||
const DEPRECATED_FEATURES = "https://developer.amazon.com/en-US/docs/alexa/ask-overviews/deprecated-features.html";
|
||||
const TABLE = [
|
||||
["Alexa.ApplicationStateReporter", "1", [], "https://developer.amazon.com/docs/alexaplus/alexa-voice-service/alexa-applicationstatereporter.html"],
|
||||
["Alexa.Audio.PlayQueue", "1", [], "alexa-audio-playqueue.html"],
|
||||
["Alexa.AuthorizationController", "1", [], DEPRECATED_FEATURES],
|
||||
["Alexa.AutomationManagement", "1", ["automationStatuses"], "alexa-automationmanagement.html"],
|
||||
["Alexa.Automotive.VehicleData", "1", [], DEPRECATED_FEATURES],
|
||||
// 1.5.2 announced the version "UNKNOWN"; 1.7 is what the list of interfaces gives
|
||||
["Alexa.Camera.LiveViewController", "1.7", [], LIST_OF_INTERFACES],
|
||||
["Alexa.CameraStreamController", "3", [], "alexa-camerastreamcontroller.html"],
|
||||
["Alexa.ChannelController", "3", ["channel"], "alexa-channelcontroller.html"],
|
||||
["Alexa.ColorController", "3", ["color"], "alexa-colorcontroller.html"],
|
||||
["Alexa.ColorTemperatureController", "3", ["colorTemperatureInKelvin"], "alexa-colortemperaturecontroller.html"],
|
||||
["Alexa.Commissionable", "1", [], "alexa-commissionable.html"],
|
||||
["Alexa.ConsentManagement.ConsentRequiredReporter", "1", [], "alexa-consentrequiredreporter.html"],
|
||||
["Alexa.ContactSensor", "3", ["detectionState"], "alexa-contactsensor.html"],
|
||||
["Alexa.Cooking", "1", [], "alexa-cooking.html"],
|
||||
["Alexa.Cooking.FoodTemperatureController", "1", [], "alexa-cooking-foodtemperaturecontroller.html"],
|
||||
["Alexa.Cooking.FoodTemperatureSensor", "1", [], "alexa-cooking-foodtemperaturesensor.html"],
|
||||
["Alexa.Cooking.PresetController", "1", [], "alexa-cooking-presetcontroller.html"],
|
||||
["Alexa.Cooking.TemperatureController", "1", [], "alexa-cooking-temperaturecontroller.html"],
|
||||
["Alexa.Cooking.TemperatureSensor", "1", [], "alexa-cooking-temperaturesensor.html"],
|
||||
["Alexa.Cooking.TimeController", "1", [], "alexa-cooking-timecontroller.html"],
|
||||
["Alexa.DataController", "1", [], "alexa-datacontroller.html"],
|
||||
["Alexa.DeviceUsage.Estimation", "1", [], "alexa-deviceusage-estimation.html"],
|
||||
["Alexa.DeviceUsage.Meter", "1", [], "alexa-deviceusage-meter.html"],
|
||||
["Alexa.DoorbellEventSource", "3", [], "alexa-doorbelleventsource.html"],
|
||||
["Alexa.EqualizerController", "1", [], "alexa-equalizercontroller.html"],
|
||||
["Alexa.InputController", "3", [], "alexa-inputcontroller.html"],
|
||||
["Alexa.InventoryLevelSensor", "1", [], "alexa-inventorylevelsensor.html"],
|
||||
["Alexa.InventoryLevelUsageSensor", "1", [], "alexa-inventorylevelusagesensor.html"],
|
||||
["Alexa.InventoryUsageSensor", "1", [], "alexa-inventoryusagesensor.html"],
|
||||
["Alexa.KeypadController", "1", [], "alexa-keypadcontroller.html"],
|
||||
["Alexa.Launcher", "1.1", [], "alexa-launcher.html"],
|
||||
["Alexa.LockController", "3", [], "alexa-lockcontroller.html"],
|
||||
["Alexa.Media.PlayQueue", "1", [], "alexa-media-playqueue.html"],
|
||||
["Alexa.Media.Playback", "1", [], "alexa-media-playback.html"],
|
||||
["Alexa.Media.Search", "1", [], "alexa-media-search.html"],
|
||||
["Alexa.ModeController", "3", ["mode"], "alexa-modecontroller.html"],
|
||||
["Alexa.MotionSensor", "3", [], "alexa-motionsensor.html"],
|
||||
["Alexa.PercentageController", "3", [], "alexa-percentagecontroller.html"],
|
||||
["Alexa.PlaybackController", "3", [], "alexa-playbackcontroller.html"],
|
||||
["Alexa.PlaybackStateReporter", "1", [], "alexa-playbackcontroller.html"],
|
||||
["Alexa.PowerLevelController", "3", [], "alexa-powerlevelcontroller.html"],
|
||||
["Alexa.ProactiveNotificationSource", "1", [], "alexa-proactivenotificationsource.html"],
|
||||
["Alexa.RTCSessionController", "1", [], "alexa-rtcsessioncontroller.html"],
|
||||
["Alexa.RangeController", "3", [], "alexa-rangecontroller.html"],
|
||||
["Alexa.RecordController", "3", [], "alexa-recordcontroller.html"],
|
||||
["Alexa.RemoteVideoPlayer", "1", [], "alexa-remotevideoplayer.html"],
|
||||
["Alexa.SceneController", "3", [], "alexa-scenecontroller.html"],
|
||||
["Alexa.SecurityPanelController", "1", [], "alexa-securitypanelcontroller.html"],
|
||||
["Alexa.SecurityPanelController.Alert", "1", [], "alexa-securitypanelcontroller-alert.html"],
|
||||
["Alexa.SeekController", "3", [], "alexa-seekcontroller.html"],
|
||||
["Alexa.SimpleEventSource", "1", [], "alexa-simpleeventsource.html"],
|
||||
["Alexa.SmartVision.ObjectDetectionSensor", "1", [], "alexa-smartvision-objectdetectionsensor.html"],
|
||||
["Alexa.SmartVision.SnapshotProvider", "1", [], "alexa-smartvision-snapshotprovider.html"],
|
||||
["Alexa.Speaker", "1", [], "alexa-speaker.html"],
|
||||
["Alexa.StepSpeaker", "1", [], "alexa-stepspeaker.html"],
|
||||
["Alexa.ThermostatController", "3.2", ["targetSetpoint", "lowerSetpoint", "upperSetpoint", "thermostatMode"], "alexa-thermostatcontroller.html"],
|
||||
["Alexa.ThermostatController.Configuration", "1", [], "alexa-thermostatcontroller-configuration.html"],
|
||||
["Alexa.ThermostatController.HVAC.Components", "1", [], "alexa-thermostatcontroller-hvac-components.html"],
|
||||
["Alexa.ThermostatController.Schedule", "1", [], "alexa-thermostatcontroller-schedule.html"],
|
||||
// "UNKNOWN" in 1.5.2 as well; the page is titled "Interface 3"
|
||||
["Alexa.TimeHoldController", "3", [], "alexa-timeholdcontroller.html"],
|
||||
["Alexa.ToggleController", "3", ["toggleState"], "alexa-togglecontroller.html"],
|
||||
["Alexa.UIController", "1", [], "alexa-uicontroller.html"],
|
||||
["Alexa.UserPreference", "1", [], "alexa-userpreference.html"],
|
||||
["Alexa.VideoRecorder", "1", [], "alexa-videorecorder.html"],
|
||||
["Alexa.WakeOnLANController", "1", [], "alexa-wakeonlancontroller.html"],
|
||||
];
|
||||
function kindOf(namespace) {
|
||||
if (namespace.endsWith("Sensor"))
|
||||
return "sensor";
|
||||
if (namespace.endsWith("EventSource"))
|
||||
return "eventSource";
|
||||
return "controller";
|
||||
}
|
||||
function stub([namespace, version, properties, page]) {
|
||||
return {
|
||||
namespace,
|
||||
version,
|
||||
doc: page.startsWith("https://") ? page : `${DEVICE_APIS}/${page}`,
|
||||
kind: kindOf(namespace),
|
||||
tier: 3,
|
||||
instanced: false,
|
||||
properties: Object.fromEntries(properties.map((name) => [name, { name, value: schema_js_1.s.unknown() }])),
|
||||
directives: {},
|
||||
};
|
||||
}
|
||||
exports.STUBS = TABLE.map(stub);
|
||||
Loading…
Add table
Add a link
Reference in a new issue