New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

home-assistant-js-websocket

Package Overview
Dependencies
Maintainers
2
Versions
102
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

home-assistant-js-websocket - npm Package Compare versions

Comparing version 7.1.0 to 8.0.0

3

dist/auth.js

@@ -114,6 +114,5 @@ import { parseQuery } from "./util.js";

const formData = new FormData();
formData.append("action", "revoke");
formData.append("token", this.data.refresh_token);
// There is no error checking, as revoke will always return 200
await fetch(`${this.data.hassUrl}/auth/token`, {
await fetch(`${this.data.hassUrl}/auth/revoke`, {
method: "POST",

@@ -120,0 +119,0 @@ credentials: "same-origin",

@@ -11,47 +11,52 @@ /**

this._handleMessage = (event) => {
const message = JSON.parse(event.data);
if (DEBUG) {
console.log("Received", message);
let messageGroup = JSON.parse(event.data);
if (!Array.isArray(messageGroup)) {
messageGroup = [messageGroup];
}
const info = this.commands.get(message.id);
switch (message.type) {
case "event":
if (info) {
info.callback(message.event);
}
else {
console.warn(`Received event for unknown subscription ${message.id}. Unsubscribing.`);
this.sendMessagePromise(messages.unsubscribeEvents(message.id));
}
break;
case "result":
// No info is fine. If just sendMessage is used, we did not store promise for result
if (info) {
if (message.success) {
info.resolve(message.result);
// Don't remove subscriptions.
if (!("subscribe" in info)) {
messageGroup.forEach((message) => {
if (DEBUG) {
console.log("Received", message);
}
const info = this.commands.get(message.id);
switch (message.type) {
case "event":
if (info) {
info.callback(message.event);
}
else {
console.warn(`Received event for unknown subscription ${message.id}. Unsubscribing.`);
this.sendMessagePromise(messages.unsubscribeEvents(message.id));
}
break;
case "result":
// No info is fine. If just sendMessage is used, we did not store promise for result
if (info) {
if (message.success) {
info.resolve(message.result);
// Don't remove subscriptions.
if (!("subscribe" in info)) {
this.commands.delete(message.id);
}
}
else {
info.reject(message.error);
this.commands.delete(message.id);
}
}
else {
info.reject(message.error);
break;
case "pong":
if (info) {
info.resolve();
this.commands.delete(message.id);
}
}
break;
case "pong":
if (info) {
info.resolve();
this.commands.delete(message.id);
}
else {
console.warn(`Received unknown pong response ${message.id}`);
}
break;
default:
if (DEBUG) {
console.warn("Unhandled message", message);
}
}
else {
console.warn(`Received unknown pong response ${message.id}`);
}
break;
default:
if (DEBUG) {
console.warn("Unhandled message", message);
}
}
});
};

@@ -124,3 +129,3 @@ this._handleClose = async () => {

// id if next command to send
this.commandId = 1;
this.commandId = 2; // socket may send 1 at the start to enable features
// info about active subscriptions and commands in flight

@@ -127,0 +132,0 @@ this.commands = new Map();

@@ -19,2 +19,9 @@ (function (global, factory) {

}
function supportedFeatures() {
return {
type: "supported_features",
id: 1,
features: { coalesce_messages: 1 },
};
}
function states() {

@@ -83,2 +90,52 @@ return {

function parseQuery(queryString) {
const query = {};
const items = queryString.split("&");
for (let i = 0; i < items.length; i++) {
const item = items[i].split("=");
const key = decodeURIComponent(item[0]);
const value = item.length > 1 ? decodeURIComponent(item[1]) : undefined;
query[key] = value;
}
return query;
}
// From: https://davidwalsh.name/javascript-debounce-function
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
// eslint-disable-next-line: ban-types
const debounce = (func, wait, immediate = false) => {
let timeout;
// @ts-ignore
return function (...args) {
// @ts-ignore
const context = this;
const later = () => {
timeout = undefined;
if (!immediate) {
func.apply(context, args);
}
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
func.apply(context, args);
}
};
};
const atLeastHaVersion = (version, major, minor, patch) => {
const [haMajor, haMinor, haPatch] = version.split(".", 3);
return (Number(haMajor) > major ||
(Number(haMajor) === major &&
(patch === undefined
? Number(haMinor) >= minor
: Number(haMinor) > minor)) ||
(patch !== undefined &&
Number(haMajor) === major &&
Number(haMinor) === minor &&
Number(haPatch) >= patch));
};
/**

@@ -154,2 +211,5 @@ * Create a web socket connection with a Home Assistant instance.

socket.haVersion = message.ha_version;
if (atLeastHaVersion(socket.haVersion, 2022, 9)) {
socket.send(JSON.stringify(supportedFeatures()));
}
promResolve(socket);

@@ -174,40 +234,45 @@ break;

this._handleMessage = (event) => {
const message = JSON.parse(event.data);
const info = this.commands.get(message.id);
switch (message.type) {
case "event":
if (info) {
info.callback(message.event);
}
else {
console.warn(`Received event for unknown subscription ${message.id}. Unsubscribing.`);
this.sendMessagePromise(unsubscribeEvents(message.id));
}
break;
case "result":
// No info is fine. If just sendMessage is used, we did not store promise for result
if (info) {
if (message.success) {
info.resolve(message.result);
// Don't remove subscriptions.
if (!("subscribe" in info)) {
let messageGroup = JSON.parse(event.data);
if (!Array.isArray(messageGroup)) {
messageGroup = [messageGroup];
}
messageGroup.forEach((message) => {
const info = this.commands.get(message.id);
switch (message.type) {
case "event":
if (info) {
info.callback(message.event);
}
else {
console.warn(`Received event for unknown subscription ${message.id}. Unsubscribing.`);
this.sendMessagePromise(unsubscribeEvents(message.id));
}
break;
case "result":
// No info is fine. If just sendMessage is used, we did not store promise for result
if (info) {
if (message.success) {
info.resolve(message.result);
// Don't remove subscriptions.
if (!("subscribe" in info)) {
this.commands.delete(message.id);
}
}
else {
info.reject(message.error);
this.commands.delete(message.id);
}
}
else {
info.reject(message.error);
break;
case "pong":
if (info) {
info.resolve();
this.commands.delete(message.id);
}
}
break;
case "pong":
if (info) {
info.resolve();
this.commands.delete(message.id);
}
else {
console.warn(`Received unknown pong response ${message.id}`);
}
break;
}
else {
console.warn(`Received unknown pong response ${message.id}`);
}
break;
}
});
};

@@ -277,3 +342,3 @@ this._handleClose = async () => {

// id if next command to send
this.commandId = 1;
this.commandId = 2; // socket may send 1 at the start to enable features
// info about active subscriptions and commands in flight

@@ -477,52 +542,2 @@ this.commands = new Map();

function parseQuery(queryString) {
const query = {};
const items = queryString.split("&");
for (let i = 0; i < items.length; i++) {
const item = items[i].split("=");
const key = decodeURIComponent(item[0]);
const value = item.length > 1 ? decodeURIComponent(item[1]) : undefined;
query[key] = value;
}
return query;
}
// From: https://davidwalsh.name/javascript-debounce-function
// Returns a function, that, as long as it continues to be invoked, will not
// be triggered. The function will be called after it stops being called for
// N milliseconds. If `immediate` is passed, trigger the function on the
// leading edge, instead of the trailing.
// eslint-disable-next-line: ban-types
const debounce = (func, wait, immediate = false) => {
let timeout;
// @ts-ignore
return function (...args) {
// @ts-ignore
const context = this;
const later = () => {
timeout = undefined;
if (!immediate) {
func.apply(context, args);
}
};
const callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) {
func.apply(context, args);
}
};
};
const atLeastHaVersion = (version, major, minor, patch) => {
const [haMajor, haMinor, haPatch] = version.split(".", 3);
return (Number(haMajor) > major ||
(Number(haMajor) === major &&
(patch === undefined
? Number(haMinor) >= minor
: Number(haMinor) > minor)) ||
(patch !== undefined &&
Number(haMajor) === major &&
Number(haMinor) === minor &&
Number(haPatch) >= patch));
};
const genClientId = () => `${location.protocol}//${location.host}/`;

@@ -639,6 +654,5 @@ const genExpires = (expires_in) => {

const formData = new FormData();
formData.append("action", "revoke");
formData.append("token", this.data.refresh_token);
// There is no error checking, as revoke will always return 200
await fetch(`${this.data.hassUrl}/auth/token`, {
await fetch(`${this.data.hassUrl}/auth/revoke`, {
method: "POST",

@@ -645,0 +659,0 @@ credentials: "same-origin",

@@ -6,2 +6,9 @@ import { Error, HassServiceTarget } from "./types.js";

};
export declare function supportedFeatures(): {
type: string;
id: number;
features: {
coalesce_messages: number;
};
};
export declare function states(): {

@@ -8,0 +15,0 @@ type: string;

@@ -7,2 +7,9 @@ export function auth(accessToken) {

}
export function supportedFeatures() {
return {
type: "supported_features",
id: 1,
features: { coalesce_messages: 1 },
};
}
export function states() {

@@ -9,0 +16,0 @@ return {

@@ -6,2 +6,3 @@ /**

import * as messages from "./messages.js";
import { atLeastHaVersion } from "./util.js";
const DEBUG = false;

@@ -84,2 +85,5 @@ export const MSG_TYPE_AUTH_REQUIRED = "auth_required";

socket.haVersion = message.ha_version;
if (atLeastHaVersion(socket.haVersion, 2022, 9)) {
socket.send(JSON.stringify(messages.supportedFeatures()));
}
promResolve(socket);

@@ -86,0 +90,0 @@ break;

@@ -5,3 +5,3 @@ {

"sideEffects": false,
"version": "7.1.0",
"version": "8.0.0",
"description": "Home Assistant websocket client",

@@ -40,3 +40,3 @@ "source": "lib/index.ts",

"husky": "^4.2.5",
"lint-staged": "^12.0.2",
"lint-staged": "^13.0.0",
"mocha": "^8.0.1",

@@ -43,0 +43,0 @@ "prettier": "^2.0.5",

@@ -446,20 +446,16 @@ # :aerial_tramway: JavaScript websocket client for Home Assistant

NodeJS does not have a WebSocket client built-in, but there are some good ones on NPM. We recommend ws. You will need to create your own version of createSocket and pass that to the constructor.
NodeJS does not have a WebSocket client built-in, but there are some good ones on NPM. We recommend ws. The easiest way to enable WebSocket is to polyfill it into the global namespace.
Look at https://github.com/keesschollaart81/vscode-home-assistant/blob/master/src/language-service/src/home-assistant/socket.ts as an example using ws.
If using TypeScript, you will need to add `"skipLibCheck": true` to your tsconfig.json to avoid typing errors.
If using TypeScript, you will need to install `@types/ws` as well.
```js
const WebSocket = require("ws");
globalThis.WebSocket = require("ws");
```
createConnection({
createSocket() {
// Open connection
const ws = new WebSocket("ws://localhost:8123");
or in TypeScript:
// TODO: Handle authentication with Home Assistant yourself :)
return ws;
},
});
```ts
const wnd = globalThis;
wnd.WebSocket = require("ws");
```

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc