ha-opencode 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +119 -236
- package/dist/commands.d.ts +13 -11
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +87 -135
- package/dist/commands.js.map +1 -1
- package/dist/ha-config.d.ts +42 -0
- package/dist/ha-config.d.ts.map +1 -0
- package/dist/ha-config.js +104 -0
- package/dist/ha-config.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +255 -83
- package/dist/index.js.map +1 -1
- package/dist/state.d.ts +20 -18
- package/dist/state.d.ts.map +1 -1
- package/dist/state.js +99 -108
- package/dist/state.js.map +1 -1
- package/dist/websocket.d.ts +113 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +394 -0
- package/dist/websocket.js.map +1 -0
- package/package.json +6 -5
- package/blueprints/opencode_permission_response.yaml +0 -81
- package/blueprints/opencode_state_notifications.yaml +0 -191
- package/dist/cleanup.d.ts +0 -30
- package/dist/cleanup.d.ts.map +0 -1
- package/dist/cleanup.js +0 -125
- package/dist/cleanup.js.map +0 -1
- package/dist/config.d.ts +0 -28
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -18
- package/dist/config.js.map +0 -1
- package/dist/discovery.d.ts +0 -129
- package/dist/discovery.d.ts.map +0 -1
- package/dist/discovery.js +0 -257
- package/dist/discovery.js.map +0 -1
- package/dist/mqtt.d.ts +0 -16
- package/dist/mqtt.d.ts.map +0 -1
- package/dist/mqtt.js +0 -141
- package/dist/mqtt.js.map +0 -1
package/dist/discovery.js
DELETED
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Extract the unique portion of a session ID by stripping the "ses_" prefix.
|
|
3
|
-
*/
|
|
4
|
-
export function extractSessionIdPart(sessionId) {
|
|
5
|
-
return sessionId.replace(/^ses_/, "");
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Generate device ID from session ID.
|
|
9
|
-
*/
|
|
10
|
-
export function getDeviceIdForSession(sessionId) {
|
|
11
|
-
return `opencode_${extractSessionIdPart(sessionId)}`;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Generate the availability topic for LWT configuration.
|
|
15
|
-
* This can be called before Discovery is instantiated.
|
|
16
|
-
*/
|
|
17
|
-
export function getAvailabilityTopicForSession(sessionId) {
|
|
18
|
-
const deviceId = getDeviceIdForSession(sessionId);
|
|
19
|
-
return `opencode/${deviceId}/availability`;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Create MQTT LWT (Last Will and Testament) config for availability tracking.
|
|
23
|
-
*/
|
|
24
|
-
export function createWillConfig(sessionId) {
|
|
25
|
-
return {
|
|
26
|
-
topic: getAvailabilityTopicForSession(sessionId),
|
|
27
|
-
payload: "offline",
|
|
28
|
-
retain: true,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
const ENTITY_DEFINITIONS = [
|
|
32
|
-
{
|
|
33
|
-
key: "device_id",
|
|
34
|
-
name: "Device ID",
|
|
35
|
-
icon: "mdi:identifier",
|
|
36
|
-
hasAttributes: true,
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
key: "state",
|
|
40
|
-
name: "State",
|
|
41
|
-
icon: "mdi:state-machine",
|
|
42
|
-
hasAttributes: true,
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
key: "session_title",
|
|
46
|
-
name: "Session",
|
|
47
|
-
icon: "mdi:message-text",
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
key: "model",
|
|
51
|
-
name: "Model",
|
|
52
|
-
icon: "mdi:brain",
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
key: "current_tool",
|
|
56
|
-
name: "Current Tool",
|
|
57
|
-
icon: "mdi:tools",
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
key: "tokens_input",
|
|
61
|
-
name: "Input Tokens",
|
|
62
|
-
icon: "mdi:arrow-right-bold",
|
|
63
|
-
unit: "tokens",
|
|
64
|
-
state_class: "measurement",
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
key: "tokens_output",
|
|
68
|
-
name: "Output Tokens",
|
|
69
|
-
icon: "mdi:arrow-left-bold",
|
|
70
|
-
unit: "tokens",
|
|
71
|
-
state_class: "measurement",
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
key: "cost",
|
|
75
|
-
name: "Cost",
|
|
76
|
-
icon: "mdi:currency-usd",
|
|
77
|
-
unit: "USD",
|
|
78
|
-
state_class: "total_increasing",
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
key: "last_activity",
|
|
82
|
-
name: "Last Activity",
|
|
83
|
-
icon: "mdi:clock-outline",
|
|
84
|
-
device_class: "timestamp",
|
|
85
|
-
},
|
|
86
|
-
{
|
|
87
|
-
key: "permission",
|
|
88
|
-
name: "Permission Request",
|
|
89
|
-
icon: "mdi:shield-alert",
|
|
90
|
-
hasAttributes: true,
|
|
91
|
-
},
|
|
92
|
-
];
|
|
93
|
-
export class Discovery {
|
|
94
|
-
mqtt;
|
|
95
|
-
haConfig;
|
|
96
|
-
deviceId;
|
|
97
|
-
device;
|
|
98
|
-
stateTopicBase;
|
|
99
|
-
sessionId;
|
|
100
|
-
projectName;
|
|
101
|
-
constructor(mqtt, haConfig, sessionId, projectName) {
|
|
102
|
-
this.mqtt = mqtt;
|
|
103
|
-
this.haConfig = haConfig;
|
|
104
|
-
this.sessionId = sessionId;
|
|
105
|
-
this.projectName = projectName;
|
|
106
|
-
// Create device ID from session ID (strip ses_ prefix, use full remaining ID)
|
|
107
|
-
this.deviceId = getDeviceIdForSession(sessionId);
|
|
108
|
-
// Initial device name uses project name with "Untitled" placeholder
|
|
109
|
-
this.device = {
|
|
110
|
-
identifiers: [this.deviceId],
|
|
111
|
-
name: `OpenCode - ${projectName} - Untitled`,
|
|
112
|
-
manufacturer: "OpenCode",
|
|
113
|
-
model: "AI Coding Assistant",
|
|
114
|
-
sw_version: sessionId,
|
|
115
|
-
};
|
|
116
|
-
this.stateTopicBase = `opencode/${this.deviceId}`;
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Update the device friendly name when session title becomes available.
|
|
120
|
-
* This re-publishes all entity configs with the updated device name.
|
|
121
|
-
*/
|
|
122
|
-
async updateDeviceName(title) {
|
|
123
|
-
this.device.name = `OpenCode - ${this.projectName} - ${title}`;
|
|
124
|
-
// Re-register all entities with updated device info
|
|
125
|
-
await this.registerDevice();
|
|
126
|
-
}
|
|
127
|
-
async registerDevice() {
|
|
128
|
-
for (const entity of ENTITY_DEFINITIONS) {
|
|
129
|
-
await this.registerEntity(entity);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
async registerEntity(entity) {
|
|
133
|
-
const uniqueId = `${this.deviceId}_${entity.key}`;
|
|
134
|
-
const configTopic = `${this.haConfig.discoveryPrefix}/sensor/${this.deviceId}/${entity.key}/config`;
|
|
135
|
-
const config = {
|
|
136
|
-
name: entity.name,
|
|
137
|
-
unique_id: uniqueId,
|
|
138
|
-
state_topic: this.getStateTopic(entity.key),
|
|
139
|
-
device: this.device,
|
|
140
|
-
// Availability tracking - entities show as unavailable when plugin disconnects
|
|
141
|
-
availability_topic: this.getAvailabilityTopic(),
|
|
142
|
-
payload_available: "online",
|
|
143
|
-
payload_not_available: "offline",
|
|
144
|
-
};
|
|
145
|
-
if (entity.icon) {
|
|
146
|
-
config.icon = entity.icon;
|
|
147
|
-
}
|
|
148
|
-
if ("unit" in entity && entity.unit) {
|
|
149
|
-
config.unit_of_measurement = entity.unit;
|
|
150
|
-
}
|
|
151
|
-
if ("state_class" in entity && entity.state_class) {
|
|
152
|
-
config.state_class = entity.state_class;
|
|
153
|
-
}
|
|
154
|
-
if ("device_class" in entity && entity.device_class) {
|
|
155
|
-
config.device_class = entity.device_class;
|
|
156
|
-
}
|
|
157
|
-
if ("hasAttributes" in entity && entity.hasAttributes) {
|
|
158
|
-
config.json_attributes_topic = this.getAttributesTopic(entity.key);
|
|
159
|
-
}
|
|
160
|
-
await this.mqtt.publish(configTopic, config, true);
|
|
161
|
-
}
|
|
162
|
-
getStateTopic(key) {
|
|
163
|
-
return `${this.stateTopicBase}/${key}`;
|
|
164
|
-
}
|
|
165
|
-
getAttributesTopic(key) {
|
|
166
|
-
return `${this.stateTopicBase}/${key}/attributes`;
|
|
167
|
-
}
|
|
168
|
-
getCommandTopic() {
|
|
169
|
-
return `${this.stateTopicBase}/command`;
|
|
170
|
-
}
|
|
171
|
-
getResponseTopic() {
|
|
172
|
-
return `${this.stateTopicBase}/response`;
|
|
173
|
-
}
|
|
174
|
-
getAvailabilityTopic() {
|
|
175
|
-
return `${this.stateTopicBase}/availability`;
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Publish online status. Call this after device registration.
|
|
179
|
-
*/
|
|
180
|
-
async publishAvailable() {
|
|
181
|
-
await this.mqtt.publish(this.getAvailabilityTopic(), "online", true);
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Publish offline status. Call this before graceful shutdown.
|
|
185
|
-
*/
|
|
186
|
-
async publishUnavailable() {
|
|
187
|
-
await this.mqtt.publish(this.getAvailabilityTopic(), "offline", true);
|
|
188
|
-
}
|
|
189
|
-
async publishState(key, value) {
|
|
190
|
-
const topic = this.getStateTopic(key);
|
|
191
|
-
let payload;
|
|
192
|
-
if (typeof value === "number") {
|
|
193
|
-
// Use decimal formatting only for cost, integers for token counts
|
|
194
|
-
payload = key === "cost" ? value.toFixed(6) : String(value);
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
payload = value;
|
|
198
|
-
}
|
|
199
|
-
await this.mqtt.publish(topic, payload, true);
|
|
200
|
-
}
|
|
201
|
-
async publishAttributes(key, attributes) {
|
|
202
|
-
const topic = this.getAttributesTopic(key);
|
|
203
|
-
await this.mqtt.publish(topic, attributes, true);
|
|
204
|
-
}
|
|
205
|
-
async publishDeviceInfo() {
|
|
206
|
-
await this.publishState("device_id", this.deviceId);
|
|
207
|
-
await this.publishAttributes("device_id", {
|
|
208
|
-
command_topic: this.getCommandTopic(),
|
|
209
|
-
response_topic: this.getResponseTopic(),
|
|
210
|
-
state_topic_base: this.stateTopicBase,
|
|
211
|
-
device_name: this.device.name,
|
|
212
|
-
session_id: this.sessionId,
|
|
213
|
-
project_name: this.projectName,
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
async publishPermission(permission) {
|
|
217
|
-
if (permission) {
|
|
218
|
-
await this.publishState("permission", "pending");
|
|
219
|
-
// Sanitize metadata to ensure it's JSON-serializable (SDK may return Decimal objects)
|
|
220
|
-
let safeMetadata = {};
|
|
221
|
-
try {
|
|
222
|
-
safeMetadata = JSON.parse(JSON.stringify(permission.metadata));
|
|
223
|
-
}
|
|
224
|
-
catch {
|
|
225
|
-
safeMetadata = { error: "metadata not serializable" };
|
|
226
|
-
}
|
|
227
|
-
await this.publishAttributes("permission", {
|
|
228
|
-
permission_id: permission.id,
|
|
229
|
-
type: permission.type,
|
|
230
|
-
title: permission.title,
|
|
231
|
-
session_id: permission.sessionID,
|
|
232
|
-
message_id: permission.messageID,
|
|
233
|
-
call_id: permission.callID || null,
|
|
234
|
-
pattern: permission.pattern || null,
|
|
235
|
-
metadata: safeMetadata,
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
await this.publishState("permission", "none");
|
|
240
|
-
await this.publishAttributes("permission", {});
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
async unregisterDevice() {
|
|
244
|
-
// Publish empty config to remove entities
|
|
245
|
-
for (const entity of ENTITY_DEFINITIONS) {
|
|
246
|
-
const configTopic = `${this.haConfig.discoveryPrefix}/sensor/${this.deviceId}/${entity.key}/config`;
|
|
247
|
-
await this.mqtt.publish(configTopic, "", true);
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Get the list of all entity keys for cleanup purposes.
|
|
252
|
-
*/
|
|
253
|
-
static getEntityKeys() {
|
|
254
|
-
return ENTITY_DEFINITIONS.map((e) => e.key);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
//# sourceMappingURL=discovery.js.map
|
package/dist/discovery.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
package/dist/mqtt.d.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { MqttConfig } from "./config.js";
|
|
2
|
-
export type MessageHandler = (topic: string, payload: string) => void;
|
|
3
|
-
export interface MqttWillConfig {
|
|
4
|
-
topic: string;
|
|
5
|
-
payload: string;
|
|
6
|
-
retain: boolean;
|
|
7
|
-
}
|
|
8
|
-
export interface MqttWrapper {
|
|
9
|
-
publish(topic: string, payload: string | object, retain?: boolean): Promise<void>;
|
|
10
|
-
subscribe(topic: string, handler: MessageHandler): Promise<void>;
|
|
11
|
-
unsubscribe(topic: string): Promise<void>;
|
|
12
|
-
isConnected(): boolean;
|
|
13
|
-
close(): Promise<void>;
|
|
14
|
-
}
|
|
15
|
-
export declare function connectMqtt(config: MqttConfig, will?: MqttWillConfig): Promise<MqttWrapper>;
|
|
16
|
-
//# sourceMappingURL=mqtt.d.ts.map
|
package/dist/mqtt.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mqtt.d.ts","sourceRoot":"","sources":["../src/mqtt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;AAEtE,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,WAAW,IAAI,OAAO,CAAC;IACvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAsB,WAAW,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,WAAW,CAAC,CAoDjG"}
|
package/dist/mqtt.js
DELETED
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import mqtt from "mqtt";
|
|
2
|
-
export async function connectMqtt(config, will) {
|
|
3
|
-
const options = {
|
|
4
|
-
clientId: config.clientId,
|
|
5
|
-
clean: true,
|
|
6
|
-
connectTimeout: 10000,
|
|
7
|
-
reconnectPeriod: 5000,
|
|
8
|
-
};
|
|
9
|
-
if (config.username) {
|
|
10
|
-
options.username = config.username;
|
|
11
|
-
}
|
|
12
|
-
if (config.password) {
|
|
13
|
-
options.password = config.password;
|
|
14
|
-
}
|
|
15
|
-
// Configure Last Will and Testament (LWT) for availability tracking
|
|
16
|
-
if (will) {
|
|
17
|
-
options.will = {
|
|
18
|
-
topic: will.topic,
|
|
19
|
-
payload: Buffer.from(will.payload),
|
|
20
|
-
qos: 1,
|
|
21
|
-
retain: will.retain,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
const url = `mqtt://${config.host}:${config.port}`;
|
|
25
|
-
return new Promise((resolve, reject) => {
|
|
26
|
-
const client = mqtt.connect(url, options);
|
|
27
|
-
let connected = false;
|
|
28
|
-
const timeout = setTimeout(() => {
|
|
29
|
-
if (!connected) {
|
|
30
|
-
client.end(true);
|
|
31
|
-
reject(new Error(`MQTT connection timeout to ${url}`));
|
|
32
|
-
}
|
|
33
|
-
}, options.connectTimeout);
|
|
34
|
-
client.on("connect", () => {
|
|
35
|
-
connected = true;
|
|
36
|
-
clearTimeout(timeout);
|
|
37
|
-
resolve(createWrapper(client));
|
|
38
|
-
});
|
|
39
|
-
client.on("error", (err) => {
|
|
40
|
-
if (!connected) {
|
|
41
|
-
clearTimeout(timeout);
|
|
42
|
-
client.end(true); // Stop reconnection attempts
|
|
43
|
-
reject(err);
|
|
44
|
-
}
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Check if a topic matches a pattern with MQTT wildcards.
|
|
50
|
-
* + matches a single level, # matches multiple levels.
|
|
51
|
-
*/
|
|
52
|
-
function topicMatchesPattern(topic, pattern) {
|
|
53
|
-
const topicParts = topic.split("/");
|
|
54
|
-
const patternParts = pattern.split("/");
|
|
55
|
-
for (let i = 0; i < patternParts.length; i++) {
|
|
56
|
-
const patternPart = patternParts[i];
|
|
57
|
-
if (patternPart === "#") {
|
|
58
|
-
// # matches everything from this point
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
if (i >= topicParts.length) {
|
|
62
|
-
// Topic is shorter than pattern
|
|
63
|
-
return false;
|
|
64
|
-
}
|
|
65
|
-
if (patternPart !== "+" && patternPart !== topicParts[i]) {
|
|
66
|
-
// Not a wildcard and doesn't match
|
|
67
|
-
return false;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
// Pattern and topic must be same length (unless pattern ends with #)
|
|
71
|
-
return topicParts.length === patternParts.length;
|
|
72
|
-
}
|
|
73
|
-
function createWrapper(client) {
|
|
74
|
-
const handlers = new Map();
|
|
75
|
-
client.on("message", (topic, payload) => {
|
|
76
|
-
// Check all registered patterns for a match
|
|
77
|
-
for (const [pattern, handler] of handlers) {
|
|
78
|
-
if (topicMatchesPattern(topic, pattern)) {
|
|
79
|
-
try {
|
|
80
|
-
handler(topic, payload.toString());
|
|
81
|
-
}
|
|
82
|
-
catch (err) {
|
|
83
|
-
console.error(`[ha-opencode] Error handling message on ${topic}:`, err);
|
|
84
|
-
}
|
|
85
|
-
break; // Only call first matching handler
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
return {
|
|
90
|
-
publish(topic, payload, retain = false) {
|
|
91
|
-
return new Promise((resolve, reject) => {
|
|
92
|
-
const message = typeof payload === "string" ? payload : JSON.stringify(payload);
|
|
93
|
-
client.publish(topic, message, { qos: 1, retain }, (err) => {
|
|
94
|
-
if (err) {
|
|
95
|
-
reject(err);
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
resolve();
|
|
99
|
-
}
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
},
|
|
103
|
-
subscribe(topic, handler) {
|
|
104
|
-
return new Promise((resolve, reject) => {
|
|
105
|
-
client.subscribe(topic, { qos: 1 }, (err) => {
|
|
106
|
-
if (err) {
|
|
107
|
-
reject(err);
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
handlers.set(topic, handler);
|
|
111
|
-
resolve();
|
|
112
|
-
}
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
},
|
|
116
|
-
unsubscribe(topic) {
|
|
117
|
-
return new Promise((resolve, reject) => {
|
|
118
|
-
client.unsubscribe(topic, (err) => {
|
|
119
|
-
if (err) {
|
|
120
|
-
reject(err);
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
handlers.delete(topic);
|
|
124
|
-
resolve();
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
},
|
|
129
|
-
isConnected() {
|
|
130
|
-
return client.connected;
|
|
131
|
-
},
|
|
132
|
-
close() {
|
|
133
|
-
return new Promise((resolve) => {
|
|
134
|
-
client.end(false, {}, () => {
|
|
135
|
-
resolve();
|
|
136
|
-
});
|
|
137
|
-
});
|
|
138
|
-
},
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
//# sourceMappingURL=mqtt.js.map
|
package/dist/mqtt.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mqtt.js","sourceRoot":"","sources":["../src/mqtt.ts"],"names":[],"mappings":"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"}
|