device: the client of new Device() and setMqttClient() warn once

2.0 ignored the first argument of the Device constructor in silence and
had removed setMqttClient(), so a 1.x call threw a TypeError. Both are
deprecated shims now, as the design lists them: setMqttClient() is back
and does nothing, a client given to the constructor is ignored, and each
says once in a process what to do. The line goes to the log hook of the
bridge; a device on no bridge has none and emits a DeprecationWarning
(ALEX2NODE_DEVICE_CLIENT, ALEX2NODE_SET_MQTT_CLIENT).
null and undefined as the client warn nothing: the bridge passes null.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
David 2026-09-28 21:19:10 +00:00
parent 29ee1a315e
commit 2f6730eb52
9 changed files with 188 additions and 5 deletions

View file

@ -239,6 +239,7 @@ class Alex2MQTT extends EventEmitter {
register(device, endpointHealth) {
device.alexaInterface = this.options.alexaInterface !== false;
device.endpointHealth = endpointHealth;
device.log = (message) => this.log(message);
device.onPublishError = (err) => this.fail(err); // a failed publish is an "error" event (when listened to), never a rejected send()
// Through the dispatcher, which lets one answer to a directive pass
device.publisher = this.dispatcher.publisher;

View file

@ -73,14 +73,29 @@ declare class Device extends EventEmitter {
* is null every send() resolves "" and reports why.
*/
publisher: Publisher | null;
/** Where the device says that a call of 1.x no longer does anything. The bridge sets it to its log hook. */
log?: (message: string) => void;
/** Set by state(). */
stateProvider?: Fill;
/** Set by onReportState(). */
reportStateHandler?: DirectiveHandler<Record<string, never>>;
/** Set by onDirective(). */
directiveHandler?: DirectiveHandler;
/** client is ignored: in 1.x it was the broker client, and a device could only be built after connect(). */
/**
* client is ignored and null is what to pass: in 1.x it was the broker client, and a device could only be built
* after connect(). A device that is given one says once that it publishes through its bridge.
*
* @deprecated Removed in 3.0, with the device made by bridge.addDevice() or bridge.registerDevice().
*/
constructor(client: unknown, rootTopic: string, name: string, endpointId: string, displayCategory: Array<DisplayCategory> | null, description?: string, manufacturerName?: string, manufacturer?: string, model?: string);
/**
* Does nothing. In 1.5.2 the bridge gave its devices the new broker client after disconnect() and connect();
* they now publish through the bridge and need no client.
*
* @deprecated Removed in 3.0. Remove the call, or set device.publisher to publish somewhere else.
*/
setMqttClient(_client: unknown): void;
private deprecated;
getName(): string;
setName(name: string): void;
getEndpointId(): string;

View file

@ -13,8 +13,15 @@ import * as topics from "../topics.js";
import { send } from "../transport.js";
import { Capability, commonOptions } from "./Capability.js";
import { checkCapability, checkCapabilityCount, checkEndpoint } from "./validate.js";
// The 1.x calls that were reported as no longer doing anything: each is said once in a process
const reported = new Set();
class Device extends EventEmitter {
/** client is ignored: in 1.x it was the broker client, and a device could only be built after connect(). */
/**
* client is ignored and null is what to pass: in 1.x it was the broker client, and a device could only be built
* after connect(). A device that is given one says once that it publishes through its bridge.
*
* @deprecated Removed in 3.0, with the device made by bridge.addDevice() or bridge.registerDevice().
*/
constructor(client, rootTopic, name, endpointId, displayCategory, description = "Alexa to Node.js bridge", manufacturerName = "Alex2Node", manufacturer = "Alex2Node", model = "Alex2Node_v1.0.0") {
super();
this.rootTopic = rootTopic;
@ -46,6 +53,31 @@ class Device extends EventEmitter {
* is null every send() resolves "" and reports why.
*/
this.publisher = null;
if (client !== null && client !== undefined) {
this.deprecated("ALEX2NODE_DEVICE_CLIENT", "new Device(client, ...) ignores the client since 2.0: nothing is published through it. "
+ "Make the device with addDevice() or registerDevice() of the bridge, or set device.publisher");
}
}
/**
* Does nothing. In 1.5.2 the bridge gave its devices the new broker client after disconnect() and connect();
* they now publish through the bridge and need no client.
*
* @deprecated Removed in 3.0. Remove the call, or set device.publisher to publish somewhere else.
*/
setMqttClient(_client) {
this.deprecated("ALEX2NODE_SET_MQTT_CLIENT", "device.setMqttClient() does nothing since 2.0: a device publishes through its bridge, over disconnect() and "
+ "connect() too. Remove the call, or set device.publisher to publish somewhere else");
}
// Through the log hook of the bridge. A device on no bridge has none and warns as Node does for a deprecation:
// once on stderr, to process.on("warning"), and not at all under --no-deprecation.
deprecated(code, message) {
if (reported.has(code))
return;
reported.add(code);
if (this.log)
this.log(`warning: ${message}`);
else
process.emitWarning(message, { type: "DeprecationWarning", code });
}
getName() {
return this.name;