messages: pure builders for every event the bridge sends
src/messages builds Response, StateReport, DeferredResponse, ErrorResponse, ChangeReport and the scene, doorbell and simple events from plain values; messageId and times are parameters, so a test compares whole objects. StateBuilder collects properties checked by the descriptors, AlexaError and AlexaErrors carry the payload fields of an error type. AlexaStatusMessage and AlexaErrorResponse move to src/compat and are written on the builders. On the wire, against 1.5.2: a DeferredResponse has no context key, a ChangeReport has no correlationToken, the namespace of an ErrorResponse follows its type, and a ChangeReport without a changed property is not published: send() resolves "" and the bridge reports an error that names the endpoint. 143 tests pass (108 before). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
2558e21787
commit
46fa06728c
68 changed files with 3410 additions and 1208 deletions
64
src/compat/AlexaErrorResponse.ts
Normal file
64
src/compat/AlexaErrorResponse.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import { randomUUID } from "crypto";
|
||||
import type { MqttClient } from "mqtt";
|
||||
import { errorResponse } from "../messages/build.js";
|
||||
import { AlexaErrors } from "../messages/errors.js";
|
||||
import type { AlexaError } from "../messages/errors.js";
|
||||
import type { ErrorResponseMessage } from "../messages/types.js";
|
||||
|
||||
/** An ErrorResponse as 1.x builds it: device.getErrorMessage(token), setErrorMessage(), send(). */
|
||||
export class AlexaErrorResponse {
|
||||
// Sent when setErrorMessage() was not called: 1.x published an empty payload, which is no ErrorResponse to Alexa
|
||||
private error: AlexaError = AlexaErrors.of("INTERNAL_ERROR", "the device answered with an error and did not say which");
|
||||
private namespace?: string;
|
||||
// One id for the message, however often toJSON() is called
|
||||
private readonly messageId = randomUUID();
|
||||
/** Where a failed publish is reported (set by the Device that built this message, 1.5.2): send() never rejects. */
|
||||
public onPublishError?: (err: Error) => void;
|
||||
|
||||
constructor(
|
||||
private readonly correlationToken: string,
|
||||
private readonly rootTopic: string,
|
||||
private readonly endpointId: string,
|
||||
private readonly mqttClient: MqttClient
|
||||
) {}
|
||||
|
||||
/**
|
||||
* The error to answer with. otherParams are the fields the type adds to the payload (validRange). The header
|
||||
* carries the namespace the type is documented under, Alexa.ThermostatController for THERMOSTAT_IS_OFF;
|
||||
* options.namespace names another.
|
||||
*/
|
||||
setErrorMessage(
|
||||
type: string,
|
||||
message: string,
|
||||
otherParams: Record<string, any> = {},
|
||||
options: { namespace?: string } = {}
|
||||
): void {
|
||||
this.error = AlexaErrors.of(type, message, otherParams);
|
||||
this.namespace = options.namespace;
|
||||
}
|
||||
|
||||
toJSON(): ErrorResponseMessage {
|
||||
const { type, alexaMessage, extra } = this.error;
|
||||
return errorResponse({
|
||||
endpointId: this.endpointId,
|
||||
messageId: this.messageId,
|
||||
correlationToken: this.correlationToken,
|
||||
type,
|
||||
message: alexaMessage,
|
||||
extra,
|
||||
namespace: this.namespace ?? this.error.namespace,
|
||||
});
|
||||
}
|
||||
|
||||
/** Resolves with the topic published to, or "" when the publish failed. Never rejects. */
|
||||
send(sendAsync = false): Promise<string> {
|
||||
const topic = `${this.rootTopic}/${this.endpointId}/${sendAsync ? "deferredResponse" : "alexaResponce"}`; // "alexaResponce" is how Alex2MQTT and Alex2ESP spell the topic
|
||||
return new Promise((resolve) => {
|
||||
this.mqttClient.publish(topic, JSON.stringify(this.toJSON()), (err) => {
|
||||
if (!err) return resolve(topic);
|
||||
if (this.onPublishError) this.onPublishError(err); // -> the bridge's "error" event (when somebody listens)
|
||||
resolve(""); // 1.5.1 rejected here, and an un-caught send() then killed the host on any broker hiccup
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue