Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
686034b
chore: move to esm
robertsLando Oct 7, 2025
d6ba802
fix: breaking changes
robertsLando Oct 7, 2025
4eb9420
fix: correct file references in utils and nodemon configurations
robertsLando Oct 7, 2025
7c4bb6b
chore: remove esbuild-register, use experimenta flag
robertsLando Oct 7, 2025
0cc76a9
fix: testss
robertsLando Oct 7, 2025
98ed4ba
fix: ui tests
robertsLando Oct 7, 2025
2eeb552
fix: update import for native-url and add postinstall script for patc…
robertsLando Oct 7, 2025
5851cbd
fix: update Node.js version in .nvmrc to v22.20.0
robertsLando Oct 7, 2025
19f1c0c
fix: refactor content reading and replacement for clarity
robertsLando Oct 7, 2025
66e4bf4
fix: use node 22 to test applicetion
robertsLando Oct 7, 2025
09717f9
fix: ensure logs are always outputted and backend status is checked
robertsLando Oct 7, 2025
6bc3f10
fix: fake stick
robertsLando Oct 7, 2025
2baf010
fix: use production code in test application
robertsLando Oct 7, 2025
a303fec
Merge branch 'master' of https://github.com/zwave-js/zwave-js-ui into…
robertsLando Oct 7, 2025
5a7b39b
fix: update backend process check to use 'npm start'
robertsLando Oct 7, 2025
69d5076
fix: circular reference
robertsLando Oct 7, 2025
7d16b86
Merge branch 'master' into move-to-esm
robertsLando Oct 8, 2025
fdd8d5d
refactor: update imports to use 'node:' prefix for built-in modules
robertsLando Oct 8, 2025
b4ca151
fix: restore esbuild meta url shim
robertsLando Oct 8, 2025
d7f93fd
fix: pkg build
robertsLando Oct 8, 2025
265c958
Merge branch 'master' into move-to-esm
robertsLando Oct 8, 2025
2cb4dbf
feat: use backend code in frontend
robertsLando Oct 8, 2025
cd619fa
feat: update zwave-js to version 15.15.1 and fix generateDocs script …
robertsLando Oct 10, 2025
0ecd12c
fix: change _getFile method visibility from public to private
robertsLando Oct 10, 2025
fe3ee83
refactor: replace fs-extra with native fs/promises methods and update…
robertsLando Oct 10, 2025
90398fb
fix path resolution on Windows
AlCalzone Oct 10, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .github/workflows/test-application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@v5
with:
node-version: '20'
node-version: '22'
cache: 'npm'

- name: Install dependencies
Expand Down Expand Up @@ -81,7 +81,8 @@ jobs:

- name: Start backend
run: |
nohup npm run server > server.log 2>&1 &
npm run build:server
nohup npm start > server.log 2>&1 &
sleep 25

- name: Test MQTT write and read
Expand All @@ -91,17 +92,20 @@ jobs:
docker exec broker mosquitto_sub -h localhost -p 1883 -t "zwave/nodeID_2/106/0/currentValue/3" -C 1

- name: Output backend logs
if: always()
run: |
sleep 5
cat server.log

- name: Output broker logs
if: always()
run: |
docker logs broker

- name: Ensure backend is running
if: always()
run: |
if ! pgrep -f "npm run server" > /dev/null; then
if ! pgrep -f "npm start" > /dev/null; then
echo "Backend crashed!" && exit 1
fi
echo "Backend is running successfully."
Expand Down
2 changes: 0 additions & 2 deletions .mocharc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
recursive: true
watch-files:
- 'test/**/*.ts'
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v20.19.4
v22.20.0
2 changes: 1 addition & 1 deletion .prettierrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module.exports = {
export default {
semi: false,
singleQuote: true,
useTabs: true,
Expand Down
55 changes: 30 additions & 25 deletions api/app.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,34 @@
import express, { Request, RequestHandler, Response, Router } from 'express'
import type { Request, RequestHandler, Response, Router } from 'express'
import express from 'express'
import history from 'connect-history-api-fallback'
import cors from 'cors'
import csrf from 'csurf'
import morgan from 'morgan'
import store, { Settings, User } from './config/store'
import Gateway, { GatewayConfig, GatewayType } from './lib/Gateway'
import jsonStore from './lib/jsonStore'
import * as loggers from './lib/logger'
import MqttClient from './lib/MqttClient'
import SocketManager from './lib/SocketManager'
import ZWaveClient, { CallAPIResult, SensorTypeScale } from './lib/ZwaveClient'
import type { Settings, User } from './config/store.ts'
import store from './config/store.ts'
import type { GatewayConfig } from './lib/Gateway.ts'
import Gateway, { GatewayType } from './lib/Gateway.ts'
import jsonStore from './lib/jsonStore.ts'
import * as loggers from './lib/logger.ts'
import MqttClient from './lib/MqttClient.ts'
import SocketManager from './lib/SocketManager.ts'
import type { CallAPIResult, SensorTypeScale } from './lib/ZwaveClient.ts'
import ZWaveClient from './lib/ZwaveClient.ts'
import multer, { diskStorage } from 'multer'
import extract from 'extract-zip'
import { serverVersion } from '@zwave-js/server'
import archiver from 'archiver'
import rateLimit from 'express-rate-limit'
import session from 'express-session'
import fs, { mkdirp, move, readdir, rm, stat } from 'fs-extra'
import { createServer as createHttpServer, Server as HttpServer } from 'http'
import { createServer as createHttpsServer } from 'https'
import fs from 'fs-extra'
import type { Server as HttpServer } from 'node:http'
import { createServer as createHttpServer } from 'node:http'
import { createServer as createHttpsServer } from 'node:https'
import jwt from 'jsonwebtoken'
import path from 'path'
import path from 'node:path'
import sessionStore from 'session-file-store'
import { Socket } from 'socket.io'
import { promisify } from 'util'
import type { Socket } from 'socket.io'
import { promisify } from 'node:util'
import { Driver, libVersion } from 'zwave-js'
import {
defaultPsw,
Expand All @@ -32,20 +37,20 @@ import {
snippetsDir,
storeDir,
tmpDir,
} from './config/app'
import {
createPlugin,
CustomPlugin,
PluginConstructor,
} from './lib/CustomPlugin'
import { inboundEvents, socketEvents } from './lib/SocketEvents'
import * as utils from './lib/utils'
import backupManager from './lib/BackupManager'
import { readFile, realpath } from 'fs/promises'
} from './config/app.ts'
import type { CustomPlugin, PluginConstructor } from './lib/CustomPlugin.ts'
import { createPlugin } from './lib/CustomPlugin.ts'
import { inboundEvents, socketEvents } from './lib/SocketEvents.ts'
import * as utils from './lib/utils.ts'
import backupManager from './lib/BackupManager.ts'
import { readFile, realpath } from 'node:fs/promises'
import { generate } from 'selfsigned'
import ZnifferManager, { ZnifferConfig } from './lib/ZnifferManager'
import type { ZnifferConfig } from './lib/ZnifferManager.ts'
import ZnifferManager from './lib/ZnifferManager.ts'
import { getAllNamedScaleGroups, getAllSensors } from '@zwave-js/core'

const { mkdirp, move, readdir, rm, stat } = fs

const createCertificate = promisify(generate)

declare module 'express-session' {
Expand Down
8 changes: 4 additions & 4 deletions api/bin/www.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
/**
* Module dependencies.
*/
import jsonStore from '../lib/jsonStore'
import store from '../config/store'
import * as conf from '../config/app'
import app, { startServer } from '../app'
import jsonStore from '../lib/jsonStore.ts'
import store from '../config/store.ts'
import * as conf from '../config/app.ts'
import app, { startServer } from '../app.ts'

console.log(
` ______ __ __ _ _____ _ _ _____ \n |___ / \\ \\ / / | |/ ____| | | | |_ _|\n / /____\\ \\ /\\ / /_ ___ _____ | | (___ | | | | | | \n / /______\\ \\/ \\/ / _\' \\ \\ / / _ \\ _ | |\\___ \\ | | | | | | \n / /__ \\ /\\ / (_| |\\ V / __/ | |__| |____) | | |__| |_| |_ \n /_____| \\/ \\/ \\__,_| \\_/ \\___| \\____/|_____/ \\____/|_____|\n`,
Expand Down
2 changes: 1 addition & 1 deletion api/config/app.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { joinPath } from '../lib/utils'
import { joinPath } from '../lib/utils.ts'
import { config } from 'dotenv'

config({ path: './.env.app' })
Expand Down
9 changes: 5 additions & 4 deletions api/config/store.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// config/store.js

import { GatewayConfig } from '../lib/Gateway'
import { MqttConfig } from '../lib/MqttClient'
import { ZnifferConfig } from '../lib/ZnifferManager'
import { ZwaveConfig, deviceConfigPriorityDir } from '../lib/ZwaveClient'
import type { GatewayConfig } from '../lib/Gateway.ts'
import type { MqttConfig } from '../lib/MqttClient.ts'
import type { ZnifferConfig } from '../lib/ZnifferManager.ts'
import type { ZwaveConfig } from '../lib/ZwaveClient.ts'
import { deviceConfigPriorityDir } from '../lib/Constants.ts'

export type StoreKeys = 'settings' | 'scenes' | 'nodes' | 'users'

Expand Down
2 changes: 1 addition & 1 deletion api/hass/configurations.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// List of Home-Assistant configuration for MQTT Discovery
// https://www.home-assistant.io/docs/mqtt/discovery/

import { HassDevice } from '../lib/ZwaveClient'
import type { HassDevice } from '../lib/ZwaveClient.ts'

type HassDeviceKey =
| 'binary_sensor'
Expand Down
2 changes: 1 addition & 1 deletion api/hass/devices.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Place here repeated patterns

import { HassDevice } from '../lib/ZwaveClient'
import type { HassDevice } from '../lib/ZwaveClient.ts'

const FAN_DIMMER: HassDevice = {
type: 'fan',
Expand Down
14 changes: 7 additions & 7 deletions api/lib/BackupManager.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import store from '../config/store'
import { module } from './logger'
import jsonStore, { STORE_BACKUP_PREFIX } from './jsonStore'
import store from '../config/store.ts'
import { module } from './logger.ts'
import jsonStore, { STORE_BACKUP_PREFIX } from './jsonStore.ts'
import Cron from 'croner'
import { readdir, unlink } from 'fs/promises'
import { nvmBackupsDir, storeBackupsDir } from '../config/app'
import { joinPath } from './utils'
import type ZwaveClient from './ZwaveClient'
import { readdir, unlink } from 'node:fs/promises'
import { nvmBackupsDir, storeBackupsDir } from '../config/app.ts'
import { joinPath } from './utils.ts'
import type ZwaveClient from './ZwaveClient.ts'

export const NVM_BACKUP_PREFIX = 'NVM_'

Expand Down
4 changes: 4 additions & 0 deletions api/lib/Constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { getMeter, getMeterScale } from '@zwave-js/core'
import { join } from 'node:path'
import { storeDir } from '../config/app.ts'

interface IGenericMap {
[key: number]: string
Expand Down Expand Up @@ -43,6 +45,8 @@ export interface IMeterCCSpecific {
meterType: number
}

export const deviceConfigPriorityDir = join(storeDir, 'config')

// https://github.com/OpenZWave/open-zwave/blob/0d94c9427bbd19e47457578bccc60b16c6679b49/config/Localization.xml#L606
const _productionMap: IGenericMap = {
0: 'instant',
Expand Down
8 changes: 4 additions & 4 deletions api/lib/CustomPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Router } from 'express'
import MqttClient from './MqttClient'
import { ModuleLogger } from './logger'
import ZwaveClient from './ZwaveClient'
import type { Router } from 'express'
import type MqttClient from './MqttClient.ts'
import type { ModuleLogger } from './logger.ts'
import type ZwaveClient from './ZwaveClient.ts'

export interface PluginContext {
zwave: ZwaveClient
Expand Down
4 changes: 2 additions & 2 deletions api/lib/EventEmitter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import EventEmitter from 'events'
import { applyMixin } from './utils'
import EventEmitter from 'node:events'
import { applyMixin } from './utils.ts'

/**
* A type-safe EventEmitter interface to use in place of Node.js's EventEmitter.
Expand Down
37 changes: 21 additions & 16 deletions api/lib/Gateway.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
import * as fs from 'fs'
import * as path from 'path'
import * as utils from './utils'
import { AlarmSensorType, SetValueAPIOptions } from 'zwave-js'
import { CommandClasses, ValueID } from '@zwave-js/core'
import * as Constants from './Constants'
import { LogLevel, module } from './logger'
import hassCfg, { ColorMode } from '../hass/configurations'
import hassDevices from '../hass/devices'
import { storeDir } from '../config/app'
import { IClientPublishOptions } from 'mqtt'
import MqttClient from './MqttClient'
import ZwaveClient, {
import * as fs from 'node:fs'
import * as path from 'node:path'
import * as utils from './utils.ts'
import type { SetValueAPIOptions } from 'zwave-js'
import { AlarmSensorType } from 'zwave-js'
import type { ValueID } from '@zwave-js/core'
import { CommandClasses } from '@zwave-js/core'
import * as Constants from './Constants.ts'
import type { LogLevel } from './logger.ts'
import { module } from './logger.ts'
import type { ColorMode } from '../hass/configurations.ts'
import hassCfg from '../hass/configurations.ts'
import hassDevices from '../hass/devices.ts'
import { storeDir } from '../config/app.ts'
import type { IClientPublishOptions } from 'mqtt'
import MqttClient from './MqttClient.ts'
import type {
AllowedApis,
CallAPIResult,
EventSource,
HassDevice,
ZUINode,
ZUIValueId,
ZUIValueIdState,
} from './ZwaveClient'
} from './ZwaveClient.ts'
import type ZwaveClient from './ZwaveClient.ts'
import Cron from 'croner'

import crypto from 'crypto'
import { IMeterCCSpecific } from './Constants'
import crypto from 'node:crypto'
import type { IMeterCCSpecific } from './Constants.ts'

const logger = module('Gateway')

Expand Down
17 changes: 8 additions & 9 deletions api/lib/MqttClient.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,26 @@
'use strict'

import {
import type {
MqttClient as Client,
IClientOptions,
IClientPublishOptions,
IClientSubscribeOptions,
connect,
} from 'mqtt'
import { connect } from 'mqtt'
import {
allSettled,
parseJSON,
sanitizeTopic,
pkgJson,
stringifyJSON,
} from './utils'
import { module } from './logger'
import { TypedEventEmitter } from './EventEmitter'
import { storeDir } from '../config/app'
} from './utils.ts'
import { module } from './logger.ts'
import { TypedEventEmitter } from './EventEmitter.ts'
import { storeDir } from '../config/app.ts'
import { ensureDir } from 'fs-extra'
import { Manager } from 'mqtt-jsonl-store'
import { join } from 'path'

const url = require('native-url')
import { join } from 'node:path'
import url from 'native-url'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd use the browser-compatible WhatWG URL API instead of an extra dependency.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

every time I tried using that I ended up reverting my changes as them are not 100% compatibile

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. I did this in Z-Wave JS to enable browser support and it worked just fine.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


const logger = module('Mqtt')

Expand Down
5 changes: 4 additions & 1 deletion api/lib/PkgFsBindings.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { FileHandle, FSStats, type FileSystem } from '@zwave-js/shared/bindings'
import type { FileHandle, FSStats } from '@zwave-js/shared/bindings'
import { type FileSystem } from '@zwave-js/shared/bindings'
import { fs as nodeFs } from '@zwave-js/core/bindings/fs/node'
import path from 'node:path'

const __filename = new URL('', import.meta.url).pathname
const __dirname = path.dirname(__filename)
// Ensures that the Z-Wave JS driver is looking for the right files in the right place
// when running inside a `pkg` bundle. In this case, it will resolve its embedded
// configuration dir to the path "/config", but the files reside in "node_modules/@zwave-js/config/config" instead.
Expand Down
11 changes: 6 additions & 5 deletions api/lib/SocketManager.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
'use strict'

import { Server as HttpServer } from 'http'
import { module } from './logger'
import { Server as SocketServer, Socket } from 'socket.io'
import { TypedEventEmitter } from './EventEmitter'
import { inboundEvents } from './SocketEvents'
import type { Server as HttpServer } from 'node:http'
import { module } from './logger.ts'
import type { Socket } from 'socket.io'
import { Server as SocketServer } from 'socket.io'
import { TypedEventEmitter } from './EventEmitter.ts'
import { inboundEvents } from './SocketEvents.ts'

const logger = module('Socket')

Expand Down
29 changes: 14 additions & 15 deletions api/lib/ZnifferManager.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import type { CorruptedFrame, Frame, ZnifferOptions } from 'zwave-js'
import {
CommandClass,
CorruptedFrame,
Frame,
isEncapsulatingCommandClass,
isMultiEncapsulatingCommandClass,
Zniffer,
ZnifferOptions,
} from 'zwave-js'
import { TypedEventEmitter } from './EventEmitter'
import { module } from './logger'
import { Server as SocketServer } from 'socket.io'
import { socketEvents } from './SocketEvents'
import { ZwaveConfig } from './ZwaveClient'
import { logsDir, storeDir } from '../config/app'
import { buffer2hex, joinPath, parseSecurityKeys } from './utils'
import { isDocker } from './utils'
import { basename } from 'path'
import { readFile } from 'fs/promises'

const loglevels = require('triple-beam').configs.npm.levels
import { TypedEventEmitter } from './EventEmitter.ts'
import { module } from './logger.ts'
import type { Server as SocketServer } from 'socket.io'
import { socketEvents } from './SocketEvents.ts'
import type { ZwaveConfig } from './ZwaveClient.ts'
import { logsDir, storeDir } from '../config/app.ts'
import { buffer2hex, joinPath, parseSecurityKeys } from './utils.ts'
import { isDocker } from './utils.ts'
import { basename } from 'node:path'
import { readFile } from 'node:fs/promises'
import tripleBeam from 'triple-beam'

const loglevels = tripleBeam.configs.npm.levels

export type ZnifferConfig = Pick<
ZwaveConfig,
Expand Down
Loading
Loading