diff --git a/.github/workflows/test-application.yml b/.github/workflows/test-application.yml index 24018d0c120..2ea7eda580f 100644 --- a/.github/workflows/test-application.yml +++ b/.github/workflows/test-application.yml @@ -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 @@ -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 @@ -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." diff --git a/.mocharc.yml b/.mocharc.yml index 716aa7cd9ba..7fd0cbb997e 100644 --- a/.mocharc.yml +++ b/.mocharc.yml @@ -1,3 +1 @@ recursive: true -watch-files: - - 'test/**/*.ts' diff --git a/.nvmrc b/.nvmrc index 70f6554c700..c004e356d66 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v20.19.4 +v22.20.0 diff --git a/.prettierrc.js b/.prettierrc.js index 51327982452..f8a62af5e3e 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -1,4 +1,4 @@ -module.exports = { +export default { semi: false, singleQuote: true, useTabs: true, diff --git a/api/app.ts b/api/app.ts index 85d03ea3777..ac14677dffc 100644 --- a/api/app.ts +++ b/api/app.ts @@ -1,29 +1,33 @@ -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 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, @@ -32,18 +36,26 @@ import { snippetsDir, storeDir, tmpDir, -} from './config/app' +} 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 { - 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' + readFile, + realpath, + readdir, + stat, + rm, + rename, + writeFile, + lstat, + mkdir, +} 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 createCertificate = promisify(generate) @@ -72,7 +84,7 @@ function multerPromise( const Storage = diskStorage({ async destination(reqD, file, callback) { - await mkdirp(tmpDir) + await utils.ensureDir(tmpDir) callback(null, tmpDir) }, filename(reqF, file, callback) { @@ -262,7 +274,7 @@ const defaultSnippets: utils.Snippet[] = [] async function loadSnippets() { const localSnippetsDir = utils.joinPath(false, 'snippets') - await mkdirp(snippetsDir) + await utils.ensureDir(snippetsDir) const files = await readdir(localSnippetsDir) for (const file of files) { @@ -329,8 +341,8 @@ async function loadCertKey(): Promise<{ let cert: string try { - cert = await fs.readFile(certFile, 'utf8') - key = await fs.readFile(keyFile, 'utf8') + cert = await readFile(certFile, 'utf8') + key = await readFile(keyFile, 'utf8') } catch (error) { // noop } @@ -349,8 +361,8 @@ async function loadCertKey(): Promise<{ key = result.private cert = result.cert - await fs.writeFile(utils.joinPath(storeDir, 'key.pem'), key) - await fs.writeFile(utils.joinPath(storeDir, 'cert.pem'), cert) + await writeFile(utils.joinPath(storeDir, 'key.pem'), key) + await writeFile(utils.joinPath(storeDir, 'cert.pem'), cert) logger.info('New cert and key created') } catch (error) { logger.error('Error creating cert and key for HTTPS', error) @@ -447,14 +459,14 @@ function setupInterceptor() { async function parseDir(dir: string): Promise { const toReturn = [] - const files = await fs.readdir(dir) + const files = await readdir(dir) for (const file of files) { try { const entry: StoreFileEntry = { name: path.basename(file), path: utils.joinPath(dir, file), } - const stats = await fs.lstat(entry.path) + const stats = await lstat(entry.path) if (stats.isDirectory()) { if (entry.path === process.env.ZWAVEJS_EXTERNAL_CONFIG) { // hide config-db @@ -1367,18 +1379,18 @@ app.get('/api/store', storeLimiter, isAuthenticated, async function (req, res) { if (req.query.path) { const reqPath = getSafePath(req) // lgtm [js/path-injection] - let stat = await fs.lstat(reqPath) + let stat = await lstat(reqPath) // check symlink is secure if (stat.isSymbolicLink()) { const realPath = await realpath(reqPath) getSafePath(realPath) - stat = await fs.lstat(realPath) + stat = await lstat(realPath) } if (stat.isFile()) { // lgtm [js/path-injection] - data = await fs.readFile(reqPath, 'utf8') + data = await readFile(reqPath, 'utf8') } else { // read directory // lgtm [js/path-injection] @@ -1411,7 +1423,7 @@ app.put('/api/store', storeLimiter, isAuthenticated, async function (req, res) { if (!isNew) { // lgtm [js/path-injection] - const stat = await fs.lstat(reqPath) + const stat = await lstat(reqPath) if (!stat.isFile()) { throw Error('Path is not a file') @@ -1420,10 +1432,10 @@ app.put('/api/store', storeLimiter, isAuthenticated, async function (req, res) { if (!isDirectory) { // lgtm [js/path-injection] - await fs.writeFile(reqPath, req.body.content, 'utf8') + await writeFile(reqPath, req.body.content, 'utf8') } else { // lgtm [js/path-injection] - await fs.mkdir(reqPath) + await mkdir(reqPath) } res.json({ success: true }) @@ -1442,7 +1454,7 @@ app.delete( const reqPath = getSafePath(req) // lgtm [js/path-injection] - await fs.remove(reqPath) + await rm(reqPath, { recursive: true, force: true }) res.json({ success: true }) } catch (error) { @@ -1460,7 +1472,7 @@ app.put( try { const files = req.body.files || [] for (const f of files) { - await fs.remove(f) + await rm(f, { recursive: true, force: true }) } res.json({ success: true }) } catch (error) { @@ -1498,7 +1510,7 @@ app.post( archive.pipe(res) for (const f of files) { - const s = await fs.lstat(f) + const s = await lstat(f) const name = f.replace(storeDir, '') if (s.isFile()) { archive.file(f, { name }) @@ -1559,7 +1571,7 @@ app.post( const destinationPath = getSafePath( path.join(storeDir, folder, file.originalname), ) - await move(file.path, destinationPath) + await rename(file.path, destinationPath) } res.json({ success: true }) diff --git a/api/bin/www.ts b/api/bin/www.ts index d6dc20f34a9..d0bd836360c 100644 --- a/api/bin/www.ts +++ b/api/bin/www.ts @@ -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`, diff --git a/api/config/app.ts b/api/config/app.ts index 229d70ece71..91dd3911726 100644 --- a/api/config/app.ts +++ b/api/config/app.ts @@ -1,4 +1,4 @@ -import { joinPath } from '../lib/utils' +import { joinPath } from '../lib/utils.ts' import { config } from 'dotenv' config({ path: './.env.app' }) diff --git a/api/config/store.ts b/api/config/store.ts index d9a1df4f6d9..def5ad2df4f 100644 --- a/api/config/store.ts +++ b/api/config/store.ts @@ -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' diff --git a/api/hass/configurations.ts b/api/hass/configurations.ts index 1caeab5ffd0..543e5358ca3 100644 --- a/api/hass/configurations.ts +++ b/api/hass/configurations.ts @@ -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' diff --git a/api/hass/devices.ts b/api/hass/devices.ts index 749fb72ff26..55115fd9b74 100644 --- a/api/hass/devices.ts +++ b/api/hass/devices.ts @@ -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', diff --git a/api/lib/BackupManager.ts b/api/lib/BackupManager.ts index 41107625fdd..a2851bfc2c6 100644 --- a/api/lib/BackupManager.ts +++ b/api/lib/BackupManager.ts @@ -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_' diff --git a/api/lib/Constants.ts b/api/lib/Constants.ts index bc2b72ed6a6..f94b25aca2e 100644 --- a/api/lib/Constants.ts +++ b/api/lib/Constants.ts @@ -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 @@ -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', diff --git a/api/lib/CustomPlugin.ts b/api/lib/CustomPlugin.ts index be207342cf2..4d17b67f949 100644 --- a/api/lib/CustomPlugin.ts +++ b/api/lib/CustomPlugin.ts @@ -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 diff --git a/api/lib/EventEmitter.ts b/api/lib/EventEmitter.ts index 0738f61148c..46194c17d39 100644 --- a/api/lib/EventEmitter.ts +++ b/api/lib/EventEmitter.ts @@ -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. diff --git a/api/lib/Gateway.ts b/api/lib/Gateway.ts index ab0a1b6e2da..1a47800151f 100644 --- a/api/lib/Gateway.ts +++ b/api/lib/Gateway.ts @@ -1,16 +1,20 @@ -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, @@ -18,11 +22,12 @@ import ZwaveClient, { 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') diff --git a/api/lib/MqttClient.ts b/api/lib/MqttClient.ts index 024a8f0afec..f0bd720e05d 100644 --- a/api/lib/MqttClient.ts +++ b/api/lib/MqttClient.ts @@ -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' -import { ensureDir } from 'fs-extra' +} from './utils.ts' +import { module } from './logger.ts' +import { TypedEventEmitter } from './EventEmitter.ts' +import { storeDir } from '../config/app.ts' +import { ensureDir } from './utils.ts' 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' const logger = module('Mqtt') diff --git a/api/lib/PkgFsBindings.ts b/api/lib/PkgFsBindings.ts index c018b778d4b..8143865fa67 100644 --- a/api/lib/PkgFsBindings.ts +++ b/api/lib/PkgFsBindings.ts @@ -1,7 +1,11 @@ -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' +import { fileURLToPath } from 'node:url' +const __filename = fileURLToPath(new URL('', import.meta.url)) +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. diff --git a/api/lib/SocketManager.ts b/api/lib/SocketManager.ts index e768b40ccfb..7060bbc950d 100644 --- a/api/lib/SocketManager.ts +++ b/api/lib/SocketManager.ts @@ -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') diff --git a/api/lib/ZnifferManager.ts b/api/lib/ZnifferManager.ts index 39463578e8d..cc9b3970dec 100644 --- a/api/lib/ZnifferManager.ts +++ b/api/lib/ZnifferManager.ts @@ -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, diff --git a/api/lib/ZwaveClient.ts b/api/lib/ZwaveClient.ts index 82634d8290e..37fa67ff43a 100644 --- a/api/lib/ZwaveClient.ts +++ b/api/lib/ZwaveClient.ts @@ -1,88 +1,68 @@ +import type { + ConfigurationMetadata, + Firmware, + Route, + SupervisionResult, + ValueMetadataNumeric, + ValueMetadataString, + ZWaveDataRate, + FirmwareFileFormat, +} from '@zwave-js/core' import { CommandClasses, - ConfigurationMetadata, dskToString, Duration, - Firmware, isUnsupervisedOrSucceeded, - Route, RouteKind, SecurityClass, - SupervisionResult, SupervisionStatus, - ValueMetadataNumeric, - ValueMetadataString, - ZWaveDataRate, ZWaveErrorCodes, Protocols, - FirmwareFileFormat, tryUnzipFirmwareFile, extractFirmware, } from '@zwave-js/core' import { createDefaultTransportFormat } from '@zwave-js/core/bindings/log/node' import { JSONTransport } from '@zwave-js/log-transport-json' -import { isDocker } from './utils' -import { +import { isDocker } from './utils.ts' +import type { AssociationAddress, AssociationGroup, OTWFirmwareUpdateProgress, OTWFirmwareUpdateResult, - OTWFirmwareUpdateStatus, ControllerStatistics, - ControllerStatus, DataRate, - Driver, ExclusionOptions, - ExclusionStrategy, FirmwareUpdateCapabilities, FirmwareUpdateProgress, FirmwareUpdateResult, - FirmwareUpdateStatus, FLiRS, FoundNode, GetFirmwareUpdatesOptions, - guessFirmwareFileFormat, RebuildRoutesOptions, RebuildRoutesStatus, InclusionGrant, InclusionOptions, InclusionResult, - InclusionStrategy, - InterviewStage, - libVersion, LifelineHealthCheckResult, LifelineHealthCheckSummary, - MultilevelSwitchCommand, NodeInterviewFailedEventArgs, NodeStatistics, - NodeStatus, NodeType, PlannedProvisioningEntry, ProtocolVersion, - QRCodeVersion, QRProvisioningInformation, RefreshInfoOptions, - RemoveNodeReason, ReplaceNodeOptions, - RFRegion, RouteHealthCheckResult, RouteHealthCheckSummary, - ScheduleEntryLockCC, ScheduleEntryLockDailyRepeatingSchedule, - ScheduleEntryLockScheduleKind, ScheduleEntryLockSlotId, ScheduleEntryLockWeekDaySchedule, ScheduleEntryLockYearDaySchedule, - SerialAPISetupCommand, SetValueAPIOptions, - setValueFailed, SetValueResult, - SetValueStatus, - setValueWasUnsupervisedOrSucceeded, SmartStartProvisioningEntry, TranslatedValueID, - UserCodeCC, - UserIDStatus, ValueID, ValueMetadata, ValueType, @@ -104,38 +84,61 @@ import { PartialZWaveOptions, InclusionUserCallbacks, InclusionState, - ProvisioningEntryStatus, - AssociationCheckResult, LinkReliabilityCheckResult, JoinNetworkOptions, - JoinNetworkStrategy, JoinNetworkResult, +} from 'zwave-js' +import { + OTWFirmwareUpdateStatus, + ControllerStatus, + Driver, + ExclusionStrategy, + FirmwareUpdateStatus, + guessFirmwareFileFormat, + InclusionStrategy, + InterviewStage, + libVersion, + MultilevelSwitchCommand, + NodeStatus, + QRCodeVersion, + RemoveNodeReason, + RFRegion, + ScheduleEntryLockCC, + ScheduleEntryLockScheduleKind, + SerialAPISetupCommand, + setValueFailed, + SetValueStatus, + setValueWasUnsupervisedOrSucceeded, + UserCodeCC, + UserIDStatus, + ProvisioningEntryStatus, + AssociationCheckResult, + JoinNetworkStrategy, DriverMode, BatteryReplacementStatus, } from 'zwave-js' import { getEnumMemberName, parseQRCodeString } from 'zwave-js/Utils' -import { configDbDir, logsDir, nvmBackupsDir, storeDir } from '../config/app' -import store from '../config/store' -import jsonStore from './jsonStore' -import * as LogManager from './logger' -import * as utils from './utils' +import { configDbDir, logsDir, nvmBackupsDir, storeDir } from '../config/app.ts' +import store from '../config/store.ts' +import jsonStore from './jsonStore.ts' +import * as LogManager from './logger.ts' +import * as utils from './utils.ts' import { serverVersion, ZwavejsServer } from '@zwave-js/server' -import { ensureDir, exists, mkdirp, writeFile } from 'fs-extra' -import { Server as SocketServer } from 'socket.io' -import { TypedEventEmitter } from './EventEmitter' -import { GatewayValue } from './Gateway' - -import { ConfigManager, DeviceConfig } from '@zwave-js/config' -import { readFile } from 'fs/promises' -import backupManager, { NVM_BACKUP_PREFIX } from './BackupManager' -import { socketEvents } from './SocketEvents' -import { isUint8Array } from 'util/types' -import { PkgFsBindings } from './PkgFsBindings' -import { join } from 'path' -import { regionSupportsAutoPowerlevel } from './shared' - -export const deviceConfigPriorityDir = join(storeDir, 'config') +import type { Server as SocketServer } from 'socket.io' +import { TypedEventEmitter } from './EventEmitter.ts' +import type { GatewayValue } from './Gateway.ts' + +import type { DeviceConfig } from '@zwave-js/config' +import { ConfigManager } from '@zwave-js/config' +import { readFile, writeFile } from 'node:fs/promises' +import backupManager, { NVM_BACKUP_PREFIX } from './BackupManager.ts' +import { socketEvents } from './SocketEvents.ts' +import { isUint8Array } from 'node:util/types' +import { PkgFsBindings } from './PkgFsBindings.ts' +import { regionSupportsAutoPowerlevel } from './shared.ts' +import tripleBeam from 'triple-beam' +import { deviceConfigPriorityDir } from './Constants.ts' export const configManager = new ConfigManager({ deviceConfigPriorityDir, @@ -143,7 +146,7 @@ export const configManager = new ConfigManager({ const logger = LogManager.module('Z-Wave') -const loglevels = require('triple-beam').configs.npm.levels +const loglevels = tripleBeam.configs.npm.levels const NEIGHBORS_LOCK_REFRESH = 60 * 1000 @@ -2272,7 +2275,7 @@ class ZwaveClient extends TypedEventEmitter { // ensure deviceConfigPriorityDir exists to prevent warnings #2374 // lgtm [js/path-injection] - await ensureDir(zwaveOptions.storage.deviceConfigPriorityDir) + await utils.ensureDir(zwaveOptions.storage.deviceConfigPriorityDir) // when not set let zwavejs handle this based on the environment if (typeof this.cfg.enableSoftReset === 'boolean') { @@ -5108,7 +5111,7 @@ class ZwaveClient extends TypedEventEmitter { const fileName = `${NVM_BACKUP_PREFIX}${utils.fileDate()}${event}` - await mkdirp(nvmBackupsDir) + await utils.ensureDir(nvmBackupsDir) await writeFile(utils.joinPath(nvmBackupsDir, fileName + '.bin'), data) @@ -6853,7 +6856,7 @@ class ZwaveClient extends TypedEventEmitter { private async loadFakeNodes() { const filePath = utils.joinPath(true, 'fakeNodes.json') // load fake nodes from `fakeNodes.json` for testing - if (await exists(filePath)) { + if (await utils.pathExists(filePath)) { const fakeNodes = JSON.parse(await readFile(filePath, 'utf-8')) for (const node of fakeNodes) { // convert valueIds array to map diff --git a/api/lib/jsonStore.ts b/api/lib/jsonStore.ts index 92100a55122..92e7b42eed6 100644 --- a/api/lib/jsonStore.ts +++ b/api/lib/jsonStore.ts @@ -1,31 +1,45 @@ -import { readFile, writeFile } from 'jsonfile' -import { storeBackupsDir, storeDir } from '../config/app' -import { StoreFile, StoreKeys } from '../config/store' -import { module } from './logger' -import * as utils from './utils' +import jsonFile from 'jsonfile' +import { storeBackupsDir, storeDir } from '../config/app.ts' +import type { StoreFile, StoreKeys } from '../config/store.ts' +import { module } from './logger.ts' import { recursive as merge } from 'merge' import archiver from 'archiver' -import { createWriteStream } from 'fs' -import { mkdirp, existsSync } from 'fs-extra' -import { Response } from 'express' +import { createWriteStream, existsSync } from 'node:fs' +import type { Response } from 'express' +import { ensureDir, fileDate, joinPath } from './utils.ts' const logger = module('Store') export const STORE_BACKUP_PREFIX = 'store-backup_' +// Default dependencies for production use +const defaultDeps = { + readFile: jsonFile.readFile.bind(jsonFile), + writeFile: jsonFile.writeFile.bind(jsonFile), +} + +export interface StorageHelperDeps { + readFile?: typeof jsonFile.readFile + writeFile?: typeof jsonFile.writeFile +} + /** Constructor **/ export class StorageHelper { private _store: Record private config: Record + private readFile: typeof jsonFile.readFile + private writeFile: typeof jsonFile.writeFile public get store() { return this._store } - constructor() { + constructor(deps?: StorageHelperDeps) { this._store = {} as Record + this.readFile = deps?.readFile || defaultDeps.readFile + this.writeFile = deps?.writeFile || defaultDeps.writeFile } async init(config: Record) { @@ -40,12 +54,12 @@ export class StorageHelper { } async backup(res?: Response): Promise { - const backupFile = `${STORE_BACKUP_PREFIX}${utils.fileDate()}.zip` + const backupFile = `${STORE_BACKUP_PREFIX}${fileDate()}.zip` - await mkdirp(storeBackupsDir) + await ensureDir(storeBackupsDir) const fileStream = createWriteStream( - utils.joinPath(storeBackupsDir, backupFile), + joinPath(storeBackupsDir, backupFile), ) return new Promise((resolve, reject) => { @@ -78,7 +92,7 @@ export class StorageHelper { for (const model in this.config) { const config: StoreFile = this.config[model] - const filePath = utils.joinPath(storeDir, config.file) + const filePath = joinPath(storeDir, config.file) if (existsSync(filePath)) { archive.file(filePath, { name: config.file, @@ -94,7 +108,7 @@ export class StorageHelper { let err: { code: string } | undefined let data: any try { - data = await readFile(utils.joinPath(storeDir, config.file)) + data = await this.readFile(joinPath(storeDir, config.file)) } catch (error) { err = error } @@ -127,7 +141,7 @@ export class StorageHelper { } async put(model: StoreFile, data: any) { - await writeFile(utils.joinPath(storeDir, model.file), data) + await this.writeFile(joinPath(storeDir, model.file), data) this._store[model.file] = data return data } diff --git a/api/lib/logger.ts b/api/lib/logger.ts index 70bb3805fa6..becab50e517 100644 --- a/api/lib/logger.ts +++ b/api/lib/logger.ts @@ -1,16 +1,15 @@ -import DailyRotateFile, { - DailyRotateFileTransportOptions, -} from 'winston-daily-rotate-file' -import { ensureDirSync } from 'fs-extra' +import type { DailyRotateFileTransportOptions } from 'winston-daily-rotate-file' +import DailyRotateFile from 'winston-daily-rotate-file' import winston from 'winston' -import { logsDir, storeDir } from '../config/app' -import { GatewayConfig } from './Gateway' -import { DeepPartial, joinPath } from './utils' -import * as path from 'path' -import { readdir, stat, unlink } from 'fs/promises' -import { Stats } from 'fs' +import { logsDir, storeDir } from '../config/app.ts' +import type { GatewayConfig } from './Gateway.ts' +import type { DeepPartial } from './utils.ts' +import { joinPath, ensureDirSync } from './utils.ts' +import * as path from 'node:path' +import { readdir, stat, unlink } from 'node:fs/promises' +import type { Stats } from 'node:fs' import escapeStringRegexp from '@esm2cjs/escape-string-regexp' -import { PassThrough } from 'stream' +import { PassThrough } from 'node:stream' const { format, transports, addColors } = winston const { combine, timestamp, printf, colorize, splat } = format diff --git a/api/lib/utils.ts b/api/lib/utils.ts index 2cdb89817db..04fd2040d4c 100644 --- a/api/lib/utils.ts +++ b/api/lib/utils.ts @@ -1,16 +1,21 @@ -import { PartialZWaveOptions, ValueID, ZnifferOptions } from 'zwave-js' -import path, { resolve } from 'path' -import crypto from 'crypto' -import { readFileSync, statSync } from 'fs' -import type { ZwaveConfig } from './ZwaveClient' -import { isUint8Array } from 'util/types' +import type { PartialZWaveOptions, ValueID, ZnifferOptions } from 'zwave-js' +import path, { resolve } from 'node:path' +import crypto from 'node:crypto' +import { readFileSync, statSync } from 'node:fs' +import type { ZwaveConfig } from './ZwaveClient.ts' +import { isUint8Array } from 'node:util/types' +import { createRequire } from 'node:module' +import { mkdir, access } from 'node:fs/promises' +import { fileURLToPath } from 'node:url' // don't use import here, it will break the build - -export const pkgJson = require('../../package.json') +const require = createRequire(import.meta.url) +const pkg = require('../../package.json') let VERSION: string +export const pkgJson = pkg + export interface Snippet { name: string content: string @@ -79,7 +84,9 @@ export function fileDate(date?: Date) { return date.toISOString().slice(-24).replace(/\D/g, '').slice(0, 14) } -/** Where package.json is */ +export const __filename = fileURLToPath(new URL('', import.meta.url)) +export const __dirname = path.dirname(__filename) + export const basePath = __filename.endsWith('index.js') ? resolve(__dirname) // esbuild bundle : resolve(__dirname, '..', '..') @@ -174,11 +181,9 @@ export function getVersion(): string { .trim() } - VERSION = `${pkgJson.version}${ - rev ? '.' + rev.substring(0, 7) : '' - }` + VERSION = `${pkg.version}${rev ? '.' + rev.substring(0, 7) : ''}` } catch { - VERSION = pkgJson.version + VERSION = pkg.version } } @@ -422,3 +427,48 @@ export function isDocker(): boolean { return isDockerCached } + +/** + * Ensures that a directory exists. If the directory does not exist, it creates it recursively. + * @param dir The directory path to ensure + */ +export async function ensureDir(dir: string): Promise { + try { + await mkdir(dir, { recursive: true }) + } catch (err) { + // Ignore error if directory already exists + if ((err as NodeJS.ErrnoException).code !== 'EEXIST') { + throw err + } + } +} + +/** + * Synchronously ensures that a directory exists. If the directory does not exist, it creates it recursively. + * @param dir The directory path to ensure + */ +export function ensureDirSync(dir: string): void { + const { mkdirSync } = require('node:fs') + try { + mkdirSync(dir, { recursive: true }) + } catch (err) { + // Ignore error if directory already exists + if ((err as NodeJS.ErrnoException).code !== 'EEXIST') { + throw err + } + } +} + +/** + * Checks if a file or directory exists + * @param path The path to check + * @returns Promise that resolves to true if the path exists, false otherwise + */ +export async function pathExists(path: string): Promise { + try { + await access(path) + return true + } catch { + return false + } +} diff --git a/docs/guide/mqtt.md b/docs/guide/mqtt.md index ee06cb82c1c..6a5b7dfe294 100644 --- a/docs/guide/mqtt.md +++ b/docs/guide/mqtt.md @@ -98,7 +98,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -150,7 +150,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -460,7 +460,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -719,7 +719,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -851,7 +851,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -872,7 +872,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -971,7 +971,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -994,7 +994,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -1019,7 +1019,53 @@ Payload: ```json { - "args": [] + "args": [] +} +``` + + + +#### `stopLearnMode` + +```ts +stopLearnMode(): Promise; +``` + +Stops learn mode. + +
+Mqtt usage + +Topic: `zwave/_CLIENTS/ZWAVE_GATEWAY-/api/stopLearnMode/set` + +Payload: + +```json +{ + "args": [] +} +``` + +
+ +#### `startLearnMode` + +```ts +async startLearnMode(): Promise; +``` + +Starts learn mode. + +
+Mqtt usage + +Topic: `zwave/_CLIENTS/ZWAVE_GATEWAY-/api/startLearnMode/set` + +Payload: + +```json +{ + "args": [] } ``` @@ -1090,7 +1136,7 @@ Payload: async getAvailableFirmwareUpdates( nodeId: number, options?: GetFirmwareUpdatesOptions, -): Promise<{ version: string; changelog: string; channel: "stable" | "beta"; files: FirmwareUpdateFileInfo[]; downgrade: boolean; normalizedVersion: string; device: { manufacturerId: number; productType: number; productId: number; firmwareVersion: string; rfRegion?: RFRegion; }; }[]>; +): Promise<{ version: string; changelog: string; channel: "stable" | "beta"; files: FirmwareUpdateFileInfo[]; downgrade: boolean; normalizedVersion: string; region?: string; device: { manufacturerId: number; productType: number; productId: number; firmwareVersion: string; rfRegion?: RFRegion; }; }[]>; ```
@@ -1290,7 +1336,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -1313,7 +1359,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -2080,7 +2126,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -2101,7 +2147,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -2122,7 +2168,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -2319,7 +2365,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -2340,7 +2386,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` @@ -2385,7 +2431,7 @@ Payload: ```json { - "args": [] + "args": [] } ``` diff --git a/esbuild-register.js b/esbuild-register.js deleted file mode 100644 index fe3ef3752a3..00000000000 --- a/esbuild-register.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict' - -const { register } = require('esbuild-register/dist/node') - -register({ - hookMatcher(f) { - return f.endsWith('.ts') - }, - // Prevent esbuild from adding a "2" to the names of CC classes for some reason. - keepNames: true, - // Target the correct node version in transpilation - target: `node${process.versions.node}`, - // Stick to legacy decorators for now - tsconfigRaw: { - compilerOptions: { - experimentalDecorators: true, - }, - }, -}) diff --git a/esbuild.js b/esbuild.js index a679d6e4d9f..0f4d6be0d3d 100644 --- a/esbuild.js +++ b/esbuild.js @@ -1,7 +1,15 @@ -const esbuild = require('esbuild') -const { cp, stat, readFile, writeFile } = require('fs/promises') -const { exists, emptyDir } = require('fs-extra') -const { join } = require('path') +import esbuild from 'esbuild' +import { cp, stat, readFile, writeFile, rm, access } from 'fs/promises' +import { join } from 'path' + +async function pathExists(path) { + try { + await access(path) + return true + } catch { + return false + } +} const outputDir = 'build' @@ -13,13 +21,17 @@ function cleanPkgJson(json) { return json } +async function readJson(path) { + return JSON.parse(await readFile(path, 'utf-8')) +} + /** * Remove useless fields from package.json, this is needed mostly for `pkg` * otherwise it will try to bundle dependencies */ async function patchPkgJson(path) { const pkgJsonPath = join(outputDir, path, 'package.json') - const pkgJson = require('./' + pkgJsonPath) + const pkgJson = await readJson(pkgJsonPath) cleanPkgJson(pkgJson) delete pkgJson.scripts await writeFile(pkgJsonPath, JSON.stringify(pkgJson, null, 2)) @@ -75,7 +87,7 @@ async function printSize(fileName) { async function main() { const start = Date.now() // clean build folder - await emptyDir(outputDir) + await rm(outputDir, { recursive: true, force: true }) const outfile = `${outputDir}/index.js` @@ -116,7 +128,7 @@ async function main() { define: { 'import.meta.url': '__import_meta_url', }, - inject: ['esbuild-import-meta-url-shim.js'], + inject: ['./esbuild-import-meta-url-shim.js'], } await esbuild.build(config) @@ -130,9 +142,10 @@ async function main() { '__dirname, "./node_modules/@serialport/bindings-cpp"', ) .replace( - `"../../package.json"`, - `"./node_modules/@zwave-js/server/package.json"`, + `("../../package.json").version`, + `("./node_modules/@zwave-js/server/package.json").version`, ) + .replace(`("../../package.json")`, `("./package.json")`) await writeFile(outfile, content) @@ -154,7 +167,7 @@ async function main() { // copy assets to build folder for (const ext of externals) { const path = ext.startsWith('./') ? ext : `node_modules/${ext}` - if (await exists(path)) { + if (await pathExists(path)) { console.log(`Copying "${path}" to "${outputDir}" folder`) await cp(path, `${outputDir}/${path}`, { recursive: true }) } else { @@ -162,8 +175,8 @@ async function main() { } } - // create main patched packege.json - const pkgJson = require('./package.json') + // create main patched package.json + const pkgJson = await readJson('package.json') cleanPkgJson(pkgJson) pkgJson.scripts = { diff --git a/eslint.config.js b/eslint.config.js index e0117e52dbe..272ff8e8da7 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,11 +1,18 @@ -const { defineConfig, globalIgnores } = require('eslint/config') +import { defineConfig, globalIgnores } from 'eslint/config' +import { fileURLToPath } from 'url' +import { dirname } from 'path' -const globals = require('globals') -const vue = require('eslint-plugin-vue') -const vuetify = require('eslint-plugin-vuetify') -const js = require('@eslint/js') +import globals from 'globals' +import vue from 'eslint-plugin-vue' +import vuetify from 'eslint-plugin-vuetify' +import importPlugin from 'eslint-plugin-import' +import unicorn from 'eslint-plugin-unicorn' +import js from '@eslint/js' -const { FlatCompat } = require('@eslint/eslintrc') +import { FlatCompat } from '@eslint/eslintrc' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = dirname(__filename) const compat = new FlatCompat({ baseDirectory: __dirname, @@ -13,7 +20,7 @@ const compat = new FlatCompat({ allConfig: js.configs.all, }) -module.exports = defineConfig([ +export default defineConfig([ { languageOptions: { globals: { @@ -63,6 +70,11 @@ module.exports = defineConfig([ }, }, + plugins: { + import: importPlugin, + unicorn: unicorn, + }, + extends: compat.extends( 'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended-requiring-type-checking', @@ -84,6 +96,27 @@ module.exports = defineConfig([ '@typescript-eslint/no-unsafe-enum-comparison': 'off', '@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/no-require-imports': 'off', + + // Enforce type-only imports + '@typescript-eslint/consistent-type-imports': [ + 'error', + { + prefer: 'type-imports', + fixStyle: 'separate-type-imports', + }, + ], + + // Enforce .ts extensions for local imports + 'import/extensions': [ + 'error', + 'always', + { + ignorePackages: true, + }, + ], + + // Enforce node: protocol for Node.js built-in modules + 'unicorn/prefer-node-protocol': 'error', }, }, globalIgnores([ diff --git a/genereteDocs.ts b/generateDocs.ts similarity index 86% rename from genereteDocs.ts rename to generateDocs.ts index 77b56d59960..20c8988b862 100644 --- a/genereteDocs.ts +++ b/generateDocs.ts @@ -1,9 +1,14 @@ -import { MethodDeclaration, Project, SourceFile } from 'ts-morph' -import { allowedApis } from './api/lib/ZwaveClient' -import { readFile, writeFile } from 'fs/promises' +import type { MethodDeclaration, SourceFile } from 'ts-morph' +import { Project } from 'ts-morph' +import { allowedApis } from './api/lib/ZwaveClient.ts' +import { readFile, writeFile } from 'node:fs/promises' import * as prettier from 'prettier' -import { join } from 'path' +import { join } from 'node:path' +import { createRequire } from 'node:module' +const require = createRequire(import.meta.url) + +const __dirname = join(new URL(import.meta.url).pathname, '..') // Make the linter happy export async function formatWithPrettier( @@ -45,7 +50,7 @@ function printMethodDeclaration(method: MethodDeclaration): string { method.getDecorators().forEach((d) => d.remove()) const start = method.getStart() - const end = method.getBody().getStart() + const end = method.getBody()?.getStart() ?? method.getEnd() let ret = method .getText() .substring(0, end - start) @@ -54,6 +59,10 @@ function printMethodDeclaration(method: MethodDeclaration): string { ret += ': ' + method.getSignature().getReturnType().getText(method) } ret += ';' + + // remove import(xxx) from types + ret = ret.replace(/import\(([^)]+)\)\./g, '') + return fixPrinterErrors(ret) } diff --git a/nodemon.json b/nodemon.json index 2c6a1b88578..b5cc54ab7bb 100644 --- a/nodemon.json +++ b/nodemon.json @@ -2,5 +2,5 @@ "watch": ["**/*.ts", "package.json", "tsconfig.json"], "ext": "ts,json,js", "ignore": ["pkg", "store", "node_modules", "src", "dist", "server"], - "exec": "node --inspect=7004 --trace-warnings -r ./esbuild-register api/bin/www.ts" + "exec": "node --inspect=7004 --trace-warnings -r ./esbuild-register.js api/bin/www.ts" } diff --git a/package-lock.json b/package-lock.json index 6863dec8513..42ccacb4a10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,7 @@ "": { "name": "zwave-js-ui", "version": "11.4.1", + "hasInstallScript": true, "license": "MIT", "dependencies": { "@esm2cjs/escape-string-regexp": "^5.0.0", @@ -30,7 +31,6 @@ "express-rate-limit": "^7.3.1", "express-session": "^1.18.0", "extract-zip": "^2.0.1", - "fs-extra": "^11.2.0", "js-logger": "^1.6.1", "jsonfile": "^6.1.0", "jsonwebtoken": "^9.0.2", @@ -60,7 +60,7 @@ "vuetify-sonner": "^0.3.0", "winston": "^3.13.0", "winston-daily-rotate-file": "^5.0.0", - "zwave-js": "^15.15.0", + "zwave-js": "^15.15.1", "zxing-wasm": "^1.2.15" }, "bin": { @@ -82,19 +82,17 @@ "@types/express-rate-limit": "^5.1.3", "@types/express-session": "1.18.0", "@types/extract-zip": "^2.0.1", - "@types/fs-extra": "^11.0.4", "@types/jsonfile": "^6.1.4", "@types/jsonwebtoken": "^9.0.6", "@types/mocha": "^10.0.6", "@types/morgan": "^1.9.9", "@types/multer": "^1.4.11", "@types/node": "^20.14.6", - "@types/proxyquire": "^1.3.31", "@types/sinon-chai": "^3.2.12", "@typescript-eslint/eslint-plugin": "^8.45.0", "@typescript-eslint/parser": "^8.45.0", "@vitejs/plugin-vue": "^5.2.0", - "@yao-pkg/pkg": "^6.1.1", + "@yao-pkg/pkg": "^6.8.0", "c8": "^10.1.2", "chai": "^4.4.1", "chai-as-promised": "^8.0.0", @@ -102,7 +100,6 @@ "docsify": "^4.13.1", "docsify-cli": "^4.4.4", "esbuild": "^0.25.1", - "esbuild-register": "^3.5.0", "eslint": "^9.37.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-babel": "^5.3.1", @@ -110,16 +107,18 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^5.5.4", "eslint-plugin-promise": "^7.2.1", + "eslint-plugin-unicorn": "^61.0.2", "eslint-plugin-vue": "^9.26.0", "eslint-plugin-vuetify": "^2.5.3", + "esmock": "^2.7.3", "globals": "^16.4.0", "markdownlint-cli": "^0.41.0", "material-design-icons-iconfont": "^6.7.0", "mocha": "^10.4.0", "nodemon": "^3.1.3", "npm-run-all": "^4.1.5", + "patch-package": "^8.0.1", "prettier": "^3.3.2", - "proxyquire": "^2.1.3", "release-it": "^17.3.0", "rimraf": "^5.0.7", "sass": "1.77.6", @@ -128,6 +127,7 @@ "sinon-chai": "^3.7.0", "ts-morph": "^20.0.0", "ts-node": "^10.9.2", + "tsx": "^4.20.6", "typescript": "^5.9.3", "vite": "^6.0.0", "vite-plugin-pwa": "^0.21.0", @@ -172,6 +172,18 @@ "node": ">=14" } }, + "node_modules/@alcalzone/jsonl-db/node_modules/alcalzone-shared": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-4.0.8.tgz", + "integrity": "sha512-Rr0efCjNL9lw7miDvU8exL87Y42ehsLU2jUGNQUphhnlvxnTMrHeApWgoOSGZvsE2PhxC3KO7Z+VpQ/IbuV3aA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@alcalzone/jsonl-db/node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -3820,16 +3832,6 @@ "extract-zip": "*" } }, - "node_modules/@types/fs-extra": { - "version": "11.0.4", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-11.0.4.tgz", - "integrity": "sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==", - "dev": true, - "dependencies": { - "@types/jsonfile": "*", - "@types/node": "*" - } - }, "node_modules/@types/hammerjs": { "version": "2.0.45", "resolved": "https://registry.npmjs.org/@types/hammerjs/-/hammerjs-2.0.45.tgz", @@ -3935,12 +3937,6 @@ "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", "integrity": "sha512-ieXiYmgSRXUDeOntE1InxjWyvEelZGP63M+cGuquuRLuIKKT1osnkXjxev9B7d1nXSug5vpunx+gNlbVxMlC9A==" }, - "node_modules/@types/proxyquire": { - "version": "1.3.31", - "resolved": "https://registry.npmjs.org/@types/proxyquire/-/proxyquire-1.3.31.tgz", - "integrity": "sha512-uALowNG2TSM1HNPMMOR0AJwv4aPYPhqB0xlEhkeRTMuto5hjoSPZkvgu1nbPUkz3gEPAHv4sy4DmKsurZiEfRQ==", - "dev": true - }, "node_modules/@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", @@ -4500,26 +4496,26 @@ } }, "node_modules/@yao-pkg/pkg": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@yao-pkg/pkg/-/pkg-6.1.1.tgz", - "integrity": "sha512-AqVKon68/8V81vfGhmRrqUCcMZFzQNWFbBowcKNq82KND7vp17FlDwheRst4wn8bjNA2lwRTFhuQJWHA5EfETw==", + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@yao-pkg/pkg/-/pkg-6.8.0.tgz", + "integrity": "sha512-QQcMbQHlaw7dFy3Nk7XQ7Gm8DlczTBcgSQB1V068L5/2rSZ3TO4CMc7rU7DeIOOR0Pm+mb5TDR3yH4jT6nfkpw==", "dev": true, "license": "MIT", "dependencies": { "@babel/generator": "^7.23.0", "@babel/parser": "^7.23.0", "@babel/types": "^7.23.0", - "@yao-pkg/pkg-fetch": "3.5.17", + "@yao-pkg/pkg-fetch": "3.5.28", "into-stream": "^6.0.0", "minimist": "^1.2.6", "multistream": "^4.1.0", "picocolors": "^1.1.0", "picomatch": "^4.0.2", "prebuild-install": "^7.1.1", - "resolve": "^1.22.0", + "resolve": "^1.22.10", "stream-meter": "^1.0.4", "tar": "^7.4.3", - "tinyglobby": "^0.2.9", + "tinyglobby": "^0.2.11", "unzipper": "^0.12.3" }, "bin": { @@ -4530,9 +4526,9 @@ } }, "node_modules/@yao-pkg/pkg-fetch": { - "version": "3.5.17", - "resolved": "https://registry.npmjs.org/@yao-pkg/pkg-fetch/-/pkg-fetch-3.5.17.tgz", - "integrity": "sha512-2gD2K8JUwHwvFFZbwVXwmm90P0U3s8Kqiym4w7t2enTajH28LMhpXaqh/x+SzKeNwvPGoaRUhV0h2nPtWTDoDA==", + "version": "3.5.28", + "resolved": "https://registry.npmjs.org/@yao-pkg/pkg-fetch/-/pkg-fetch-3.5.28.tgz", + "integrity": "sha512-0dTu0yFgAuOp3OJBiwSZVkTMuGmvExwmG9mHKQhHkaNate5BWh6rBTzfQ0WId9DHXmg7GiT/kIyejEV0G3EHUQ==", "dev": true, "license": "MIT", "dependencies": { @@ -4541,13 +4537,28 @@ "picocolors": "^1.1.0", "progress": "^2.0.3", "semver": "^7.3.5", - "tar-fs": "^2.1.1", + "tar-fs": "^3.1.1", "yargs": "^16.2.0" }, "bin": { "pkg-fetch": "lib-es5/bin.js" } }, + "node_modules/@yao-pkg/pkg-fetch/node_modules/tar-fs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.1.tgz", + "integrity": "sha512-LZA0oaPOc2fVo82Txf3gw+AkEd38szODlptMYejQUhndHMLQ9M059uXR+AfS7DNo0NpINvSqDsvyaCrBVkptWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, "node_modules/@yao-pkg/pkg/node_modules/picomatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", @@ -4561,15 +4572,22 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/@zwave-js/cc": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/@zwave-js/cc/-/cc-15.15.0.tgz", - "integrity": "sha512-vvJGiQRYoGwr2SopCulu8TsImjLihDyJQTMhJjbjLZNw5lVbQxK8Tdn1MHCc4ZQbUPxgnTQsSG5CCFFMPvlrEw==", + "version": "15.15.1", + "resolved": "https://registry.npmjs.org/@zwave-js/cc/-/cc-15.15.1.tgz", + "integrity": "sha512-/GThIA/fYYy3AbZAxdjzXCP2WmINiEp05ReaPe7XQCkTHqArhvo+reThEJvR1f3RIOJv165ky/deT+sXkLTeew==", "license": "MIT", "dependencies": { - "@zwave-js/core": "15.15.0", - "@zwave-js/host": "15.15.0", - "@zwave-js/shared": "15.13.0", + "@zwave-js/core": "15.15.1", + "@zwave-js/host": "15.15.1", + "@zwave-js/shared": "15.15.1", "alcalzone-shared": "^5.0.0", "ansi-colors": "^4.1.3", "reflect-metadata": "^0.2.2" @@ -4581,30 +4599,21 @@ "url": "https://github.com/sponsors/AlCalzone/" } }, - "node_modules/@zwave-js/cc/node_modules/alcalzone-shared": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-5.0.0.tgz", - "integrity": "sha512-X73hgVWcrIKUUB6jZgHj5flRbTft8AAoJ2MqRKEcAX1whW3OeGkxsQ6ol4nd4/rKxd1eoCRXUGW3cIhXrXU4Sg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/@zwave-js/config": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/@zwave-js/config/-/config-15.15.0.tgz", - "integrity": "sha512-uRUxu05W+4jX+uJkV3oOm/1wNObDl/BA84jpMsM2uvwLu7LRYCTnOkPwCXis+RxX3x9uRHdvQSqv/hCL2k2D0A==", + "version": "15.15.1", + "resolved": "https://registry.npmjs.org/@zwave-js/config/-/config-15.15.1.tgz", + "integrity": "sha512-RH8ToB/+K8nPaC0iY+dAqnYB4BDULRyQUZ0KAMJ/bgzryIOdEiUtSatwrZuapGXgcix3PPvAWVibOnB7PQYROA==", "license": "MIT", "dependencies": { - "@zwave-js/core": "15.15.0", - "@zwave-js/shared": "15.13.0", + "@zwave-js/core": "15.15.1", + "@zwave-js/shared": "15.15.1", "alcalzone-shared": "^5.0.0", "ansi-colors": "^4.1.3", - "eslint": "^9.34.0", + "eslint": "^9.36.0", "json-logic-js": "^2.0.5", "json5": "^2.2.3", "pathe": "^2.0.3", - "semver": "^7.6.3", + "semver": "^7.7.2", "winston": "^3.17.0" }, "engines": { @@ -4614,23 +4623,26 @@ "url": "https://github.com/sponsors/AlCalzone/" } }, - "node_modules/@zwave-js/config/node_modules/alcalzone-shared": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-5.0.0.tgz", - "integrity": "sha512-X73hgVWcrIKUUB6jZgHj5flRbTft8AAoJ2MqRKEcAX1whW3OeGkxsQ6ol4nd4/rKxd1eoCRXUGW3cIhXrXU4Sg==", - "license": "MIT", + "node_modules/@zwave-js/config/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">=18" + "node": ">=10" } }, "node_modules/@zwave-js/core": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/@zwave-js/core/-/core-15.15.0.tgz", - "integrity": "sha512-m8bhTZ9Rv5ptUvFAM176frcPXhx9+/3jaHz7XRuz16ID8pbYzD2bTKR3nANcZyByQJHSIhGLGU3pd+LPjEsQFA==", + "version": "15.15.1", + "resolved": "https://registry.npmjs.org/@zwave-js/core/-/core-15.15.1.tgz", + "integrity": "sha512-G4QykEkTwxaoc9ZJew8Pd+aFaqDruqeUjVZbQksIlojQTPxY1H3hoRaE4Kfu/cNvvBTApY0B+ozPCrkOeFEPUA==", "license": "MIT", "dependencies": { - "@alcalzone/jsonl-db": "^3.1.1", - "@zwave-js/shared": "15.13.0", + "@alcalzone/jsonl-db": "^4.0.0", + "@zwave-js/shared": "15.15.1", "alcalzone-shared": "^5.0.0", "ansi-colors": "^4.1.3", "dayjs": "^1.11.18", @@ -4639,7 +4651,7 @@ "nrf-intel-hex": "^1.4.0", "pathe": "^2.0.3", "reflect-metadata": "^0.2.2", - "semver": "^7.6.3", + "semver": "^7.7.2", "triple-beam": "*", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0", @@ -4652,19 +4664,23 @@ "url": "https://github.com/sponsors/AlCalzone/" } }, - "node_modules/@zwave-js/core/node_modules/alcalzone-shared": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-5.0.0.tgz", - "integrity": "sha512-X73hgVWcrIKUUB6jZgHj5flRbTft8AAoJ2MqRKEcAX1whW3OeGkxsQ6ol4nd4/rKxd1eoCRXUGW3cIhXrXU4Sg==", + "node_modules/@zwave-js/core/node_modules/@alcalzone/jsonl-db": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@alcalzone/jsonl-db/-/jsonl-db-4.0.0.tgz", + "integrity": "sha512-UWLyq9FcNd+4Gv0bmy4F4v7ZOjn9LWY/VErS0xFWpKNmBb6ZuTCuWns9n60KIpaQN67UCXoVYMKNRseKC2adRg==", "license": "MIT", + "dependencies": { + "@alcalzone/proper-lockfile": "^4.1.3-0", + "alcalzone-shared": "^5.0.0" + }, "engines": { - "node": ">=18" + "node": ">=22" } }, "node_modules/@zwave-js/core/node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4674,14 +4690,14 @@ } }, "node_modules/@zwave-js/host": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/@zwave-js/host/-/host-15.15.0.tgz", - "integrity": "sha512-toACabQg4FPrP0MC5eLfLlf8e//cv5GoV44I2cOMAk95Gkj1UzH218I/mwPGIOQb+YxxtcsKQtKymAmZznqTLA==", + "version": "15.15.1", + "resolved": "https://registry.npmjs.org/@zwave-js/host/-/host-15.15.1.tgz", + "integrity": "sha512-XMAD5eOEcexpvB/OLBW5NNicymZcbRCxil6QFAc6Yt5jHqtgcAS5W16bonxy8DpykH9WBgxzmoDEPS1pukdcNA==", "license": "MIT", "dependencies": { - "@zwave-js/config": "15.15.0", - "@zwave-js/core": "15.15.0", - "@zwave-js/shared": "15.13.0", + "@zwave-js/config": "15.15.1", + "@zwave-js/core": "15.15.1", + "@zwave-js/shared": "15.15.1", "alcalzone-shared": "^5.0.0" }, "engines": { @@ -4691,15 +4707,6 @@ "url": "https://github.com/sponsors/AlCalzone/" } }, - "node_modules/@zwave-js/host/node_modules/alcalzone-shared": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-5.0.0.tgz", - "integrity": "sha512-X73hgVWcrIKUUB6jZgHj5flRbTft8AAoJ2MqRKEcAX1whW3OeGkxsQ6ol4nd4/rKxd1eoCRXUGW3cIhXrXU4Sg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/@zwave-js/log-transport-json": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@zwave-js/log-transport-json/-/log-transport-json-3.0.0.tgz", @@ -4719,16 +4726,16 @@ } }, "node_modules/@zwave-js/nvmedit": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/@zwave-js/nvmedit/-/nvmedit-15.15.0.tgz", - "integrity": "sha512-Bq2Dv+A/G1jySQjXc0Y1gvvN1iUea4lA5nWj66GRDXlQR4+Vp5JZHfH4w+NLdL+c3WBs2WVXiLVSBXVwPQTTRA==", + "version": "15.15.1", + "resolved": "https://registry.npmjs.org/@zwave-js/nvmedit/-/nvmedit-15.15.1.tgz", + "integrity": "sha512-IJawtx7zDnhYU14ociNfH8fkI2n/q59mt/RIpHp3k+IsWDdprw/PPIxCumFrIK5rujqqm9P7EjZwaVgWrULo3g==", "license": "MIT", "dependencies": { - "@zwave-js/core": "15.15.0", - "@zwave-js/shared": "15.13.0", + "@zwave-js/core": "15.15.1", + "@zwave-js/shared": "15.15.1", "alcalzone-shared": "^5.0.0", "reflect-metadata": "^0.2.2", - "semver": "^7.6.3", + "semver": "^7.7.2", "yargs": "^18.0.0" }, "bin": { @@ -4741,15 +4748,6 @@ "url": "https://github.com/sponsors/AlCalzone/" } }, - "node_modules/@zwave-js/nvmedit/node_modules/alcalzone-shared": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-5.0.0.tgz", - "integrity": "sha512-X73hgVWcrIKUUB6jZgHj5flRbTft8AAoJ2MqRKEcAX1whW3OeGkxsQ6ol4nd4/rKxd1eoCRXUGW3cIhXrXU4Sg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/@zwave-js/nvmedit/node_modules/ansi-regex": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", @@ -4794,6 +4792,18 @@ "integrity": "sha512-lb49vf1Xzfx080OKA0o6l8DQQpV+6Vg95zyCJX9VB/BqKYlhG7N4wgROUUHRA+ZPUefLnteQOad7z1kT2bV7bg==", "license": "MIT" }, + "node_modules/@zwave-js/nvmedit/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@zwave-js/nvmedit/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", @@ -4870,16 +4880,16 @@ } }, "node_modules/@zwave-js/serial": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/@zwave-js/serial/-/serial-15.15.0.tgz", - "integrity": "sha512-s9a6SGaGYolzDS1PQkGUd6VSe7Xxb2m0dZzM/sSr7xTH5uwtnD+9H9NBIg0VxOLTpjoxhf5lJIekS/38/ItUPQ==", + "version": "15.15.1", + "resolved": "https://registry.npmjs.org/@zwave-js/serial/-/serial-15.15.1.tgz", + "integrity": "sha512-yxpFezRxcmKWRAqy1y6lrVYvZLu93xdMRqi0Ie35hEK9EawA9hNIfXoBDfN994BVJGKXvWyfGTB6BFwPrCRqDw==", "license": "MIT", "dependencies": { "@serialport/stream": "^13.0.0", - "@zwave-js/cc": "15.15.0", - "@zwave-js/core": "15.15.0", - "@zwave-js/host": "15.15.0", - "@zwave-js/shared": "15.13.0", + "@zwave-js/cc": "15.15.1", + "@zwave-js/core": "15.15.1", + "@zwave-js/host": "15.15.1", + "@zwave-js/shared": "15.15.1", "alcalzone-shared": "^5.0.0", "serialport": "^13.0.0", "winston": "^3.17.0" @@ -4891,15 +4901,6 @@ "url": "https://github.com/sponsors/AlCalzone/" } }, - "node_modules/@zwave-js/serial/node_modules/alcalzone-shared": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-5.0.0.tgz", - "integrity": "sha512-X73hgVWcrIKUUB6jZgHj5flRbTft8AAoJ2MqRKEcAX1whW3OeGkxsQ6ol4nd4/rKxd1eoCRXUGW3cIhXrXU4Sg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/@zwave-js/server": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/@zwave-js/server/-/server-3.2.1.tgz", @@ -4943,9 +4944,9 @@ } }, "node_modules/@zwave-js/shared": { - "version": "15.13.0", - "resolved": "https://registry.npmjs.org/@zwave-js/shared/-/shared-15.13.0.tgz", - "integrity": "sha512-9GYxVomlaaTfBV/bfpfDu0WcN1T5VFMWhqK7/iVfekheJWQ2uePRyOCdp7wJ7zLwjwFtXGOHrOyt4nXUT0AWmQ==", + "version": "15.15.1", + "resolved": "https://registry.npmjs.org/@zwave-js/shared/-/shared-15.15.1.tgz", + "integrity": "sha512-9/NYWHKdf7QVSvYKstgaZhywxLcEjwbkqY/AWBeuuOOUgbQ3J1SWiHSKJWuWalrNdgIXbRk6tE99EwqCDYOvcw==", "license": "MIT", "dependencies": { "alcalzone-shared": "^5.0.0", @@ -4958,25 +4959,16 @@ "url": "https://github.com/sponsors/AlCalzone/" } }, - "node_modules/@zwave-js/shared/node_modules/alcalzone-shared": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-5.0.0.tgz", - "integrity": "sha512-X73hgVWcrIKUUB6jZgHj5flRbTft8AAoJ2MqRKEcAX1whW3OeGkxsQ6ol4nd4/rKxd1eoCRXUGW3cIhXrXU4Sg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/@zwave-js/testing": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/@zwave-js/testing/-/testing-15.15.0.tgz", - "integrity": "sha512-7I5ZxiZUhe77xg0Bct00xcqTmdlmDcpzs3SPVYg83SGusGA3jHvwQ2opLWdPOK4xULlJooEB+0ebskyD03OItg==", + "version": "15.15.1", + "resolved": "https://registry.npmjs.org/@zwave-js/testing/-/testing-15.15.1.tgz", + "integrity": "sha512-tEXxLdwV2QxZj2cC3C6YARq/2ZpXnw2iqHShclPp7u6gTZmGDnq/ikXLs5R9KLz/JGf1MTdmMFvvxNDp2Yd3jA==", "license": "MIT", "dependencies": { - "@zwave-js/core": "15.15.0", - "@zwave-js/host": "15.15.0", - "@zwave-js/serial": "15.15.0", - "@zwave-js/shared": "15.13.0", + "@zwave-js/core": "15.15.1", + "@zwave-js/host": "15.15.1", + "@zwave-js/serial": "15.15.1", + "@zwave-js/shared": "15.15.1", "alcalzone-shared": "^5.0.0", "ansi-colors": "^4.1.3" }, @@ -4987,15 +4979,6 @@ "url": "https://github.com/sponsors/AlCalzone/" } }, - "node_modules/@zwave-js/testing/node_modules/alcalzone-shared": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-5.0.0.tgz", - "integrity": "sha512-X73hgVWcrIKUUB6jZgHj5flRbTft8AAoJ2MqRKEcAX1whW3OeGkxsQ6ol4nd4/rKxd1eoCRXUGW3cIhXrXU4Sg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/@zwave-js/waddle": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@zwave-js/waddle/-/waddle-1.2.1.tgz", @@ -5005,15 +4988,6 @@ "alcalzone-shared": "^5.0.0" } }, - "node_modules/@zwave-js/waddle/node_modules/alcalzone-shared": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-5.0.0.tgz", - "integrity": "sha512-X73hgVWcrIKUUB6jZgHj5flRbTft8AAoJ2MqRKEcAX1whW3OeGkxsQ6ol4nd4/rKxd1eoCRXUGW3cIhXrXU4Sg==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -5104,14 +5078,12 @@ } }, "node_modules/alcalzone-shared": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-4.0.8.tgz", - "integrity": "sha512-Rr0efCjNL9lw7miDvU8exL87Y42ehsLU2jUGNQUphhnlvxnTMrHeApWgoOSGZvsE2PhxC3KO7Z+VpQ/IbuV3aA==", - "dependencies": { - "debug": "^4.3.4" - }, + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-5.0.0.tgz", + "integrity": "sha512-X73hgVWcrIKUUB6jZgHj5flRbTft8AAoJ2MqRKEcAX1whW3OeGkxsQ6ol4nd4/rKxd1eoCRXUGW3cIhXrXU4Sg==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/ansi_up": { @@ -5608,10 +5580,92 @@ } }, "node_modules/bare-events": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", - "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", - "optional": true + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.7.0.tgz", + "integrity": "sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA==", + "license": "Apache-2.0" + }, + "node_modules/bare-fs": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.4.5.tgz", + "integrity": "sha512-TCtu93KGLu6/aiGWzMr12TmSRS6nKdfhAnzTQRbXoSWxkbb9eRd53jQ51jG7g1gYjjtto3hbBrrhzg6djcgiKg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4", + "bare-url": "^2.2.2", + "fast-fifo": "^1.3.2" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.2.tgz", + "integrity": "sha512-T+V1+1srU2qYNBmJCXZkUY5vQ0B4FSlL3QDROnKQYOqeiQR8UbjNHlPa+TIbM4cuidiN9GaTaOZgSEgsvPbh5A==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.7.0.tgz", + "integrity": "sha512-oyXQNicV1y8nc2aKffH+BUHFRXmx6VrPzlnaEvMhram0nPBrKcEdcyBg5r08D0i8VxngHFAiVyn1QKXpSG0B8A==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "streamx": "^2.21.0" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, + "node_modules/bare-url": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.2.2.tgz", + "integrity": "sha512-g+ueNGKkrjMazDG3elZO1pNs3HY5+mMmOet1jtKyhOaCnkLzitxf26z7hoAEkDNgdNmnc1KIlt/dw6Po6xZMpA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-path": "^3.0.0" + } }, "node_modules/base64-js": { "version": "1.5.1", @@ -5641,6 +5695,16 @@ "node": "^4.5.0 || >= 5.9" } }, + "node_modules/baseline-browser-mapping": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.13.tgz", + "integrity": "sha512-7s16KR8io8nIBWQyCYhmFhd+ebIzb9VKTzki+wOJXHTxTnV6+mFGH3+Jwn1zoKaY9/H9T/0BcKCZnzXljPnpSQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.js" + } + }, "node_modules/basic-auth": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", @@ -5933,9 +5997,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", + "version": "4.26.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", + "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", "dev": true, "funding": [ { @@ -5953,10 +6017,11 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001669", - "electron-to-chromium": "^1.5.41", - "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.1" + "baseline-browser-mapping": "^2.8.9", + "caniuse-lite": "^1.0.30001746", + "electron-to-chromium": "^1.5.227", + "node-releases": "^2.0.21", + "update-browserslist-db": "^1.1.3" }, "bin": { "browserslist": "cli.js" @@ -6006,6 +6071,19 @@ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, + "node_modules/builtin-modules": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-5.0.0.tgz", + "integrity": "sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/bundle-name": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", @@ -6287,9 +6365,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001718", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001718.tgz", - "integrity": "sha512-AflseV1ahcSunK53NfEs9gFWgOEmzr0f+kaMFA4xiLZlr9Hzt7HxcSpIFcnNCUkz6R6dWKa54rUz3HUmI3nVcw==", + "version": "1.0.30001749", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001749.tgz", + "integrity": "sha512-0rw2fJOmLfnzCRbkm8EyHL8SvI2Apu5UbnQuTsJ0ClgrH8hcwFooJ1s5R0EP8o8aVrFu8++ae29Kt9/gZAZp/Q==", "dev": true, "funding": [ { @@ -6369,6 +6447,13 @@ "node": ">=0.8.0" } }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, "node_modules/chardet": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", @@ -6431,9 +6516,9 @@ "dev": true }, "node_modules/ci-info": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.2.0.tgz", - "integrity": "sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", "dev": true, "funding": [ { @@ -6446,6 +6531,29 @@ "node": ">=8" } }, + "node_modules/clean-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/clean-regexp/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/cli-boxes": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", @@ -7476,13 +7584,13 @@ } }, "node_modules/core-js-compat": { - "version": "3.39.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.39.0.tgz", - "integrity": "sha512-VgEUx3VwlExr5no0tXlBt+silBvhTryPwCXRI2Id1PN8WTKu7MreethvddqOubrYxkFdv/RnYrqlv1sFNAUelw==", + "version": "3.45.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.1.tgz", + "integrity": "sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==", "dev": true, "license": "MIT", "dependencies": { - "browserslist": "^4.24.2" + "browserslist": "^4.25.3" }, "funding": { "type": "opencollective", @@ -8478,9 +8586,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.63", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.63.tgz", - "integrity": "sha512-ddeXKuY9BHo/mw145axlyWjlJ1UBt4WK3AlvkT7W2AbqfRQoacVoRUCF6wL3uIx/8wT9oLKXzI+rFqHHscByaA==", + "version": "1.5.233", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.233.tgz", + "integrity": "sha512-iUdTQSf7EFXsDdQsp8MwJz5SVk4APEFqXU/S47OtQ0YLqacSwPXdZ5vRlMX3neb07Cy2vgioNuRnWUXFwuslkg==", "dev": true, "license": "ISC" }, @@ -8777,18 +8885,6 @@ "@esbuild/win32-x64": "0.25.1" } }, - "node_modules/esbuild-register": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.5.0.tgz", - "integrity": "sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==", - "dev": true, - "dependencies": { - "debug": "^4.3.4" - }, - "peerDependencies": { - "esbuild": ">=0.12 <1" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -9192,35 +9288,163 @@ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/eslint-plugin-vue": { - "version": "9.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.26.0.tgz", - "integrity": "sha512-eTvlxXgd4ijE1cdur850G6KalZqk65k1JKoOI2d1kT3hr8sPD07j1q98FRFdNnpxBELGPWxZmInxeHGF/GxtqQ==", + "node_modules/eslint-plugin-unicorn": { + "version": "61.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-61.0.2.tgz", + "integrity": "sha512-zLihukvneYT7f74GNbVJXfWIiNQmkc/a9vYBTE4qPkQZswolWNdu+Wsp9sIXno1JOzdn6OUwLPd19ekXVkahRA==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "globals": "^13.24.0", - "natural-compare": "^1.4.0", - "nth-check": "^2.1.1", - "postcss-selector-parser": "^6.0.15", - "semver": "^7.6.0", - "vue-eslint-parser": "^9.4.2", - "xml-name-validator": "^4.0.0" + "@babel/helper-validator-identifier": "^7.27.1", + "@eslint-community/eslint-utils": "^4.7.0", + "@eslint/plugin-kit": "^0.3.3", + "change-case": "^5.4.4", + "ci-info": "^4.3.0", + "clean-regexp": "^1.0.0", + "core-js-compat": "^3.44.0", + "esquery": "^1.6.0", + "find-up-simple": "^1.0.1", + "globals": "^16.3.0", + "indent-string": "^5.0.0", + "is-builtin-module": "^5.0.0", + "jsesc": "^3.1.0", + "pluralize": "^8.0.0", + "regexp-tree": "^0.1.27", + "regjsparser": "^0.12.0", + "semver": "^7.7.2", + "strip-indent": "^4.0.0" }, "engines": { - "node": "^14.17.0 || >=16.0.0" + "node": "^20.10.0 || >=21.0.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/eslint-plugin-unicorn?sponsor=1" }, "peerDependencies": { - "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + "eslint": ">=9.29.0" } }, - "node_modules/eslint-plugin-vue/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "node_modules/eslint-plugin-unicorn/node_modules/@eslint/core": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz", + "integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "type-fest": "^0.20.2" + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/@eslint/plugin-kit": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz", + "integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.2", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint-plugin-unicorn/node_modules/strip-indent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-4.1.0.tgz", + "integrity": "sha512-OA95x+JPmL7kc7zCu+e+TeYxEiaIyndRx0OrBcK2QPPH09oAndr2ALvymxWA+Lx1PYYvFUm4O63pRkdJAaW96w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.26.0.tgz", + "integrity": "sha512-eTvlxXgd4ijE1cdur850G6KalZqk65k1JKoOI2d1kT3hr8sPD07j1q98FRFdNnpxBELGPWxZmInxeHGF/GxtqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "globals": "^13.24.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.1.1", + "postcss-selector-parser": "^6.0.15", + "semver": "^7.6.0", + "vue-eslint-parser": "^9.4.2", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-vue/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" }, "engines": { "node": ">=8" @@ -9446,6 +9670,16 @@ "node": ">=8" } }, + "node_modules/esmock": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esmock/-/esmock-2.7.3.tgz", + "integrity": "sha512-/M/YZOjgyLaVoY6K83pwCsGE1AJQnj4S4GyXLYgi/Y79KL8EeW6WU7Rmjc89UO7jv6ec8+j34rKeWOfiLeEu0A==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14.16.0" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -9478,9 +9712,10 @@ } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -9552,6 +9787,15 @@ "node": ">=0.8.x" } }, + "node_modules/events-universal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz", + "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==", + "license": "Apache-2.0", + "dependencies": { + "bare-events": "^2.7.0" + } + }, "node_modules/execa": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.0.tgz", @@ -9969,19 +10213,6 @@ "node": ">=10" } }, - "node_modules/fill-keys": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", - "integrity": "sha512-tcgI872xXjwFF4xgQmLxi76GnwJG3g/3isB1l4/G5Z4zrbddGpBjqZCO9oEAcB5wX0Hj/5iQB3toxfO7in1hHA==", - "dev": true, - "dependencies": { - "is-object": "~1.0.1", - "merge-descriptors": "~1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -10078,10 +10309,11 @@ } }, "node_modules/find-up-simple": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz", - "integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -10089,6 +10321,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "micromatch": "^4.0.2" + } + }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -10260,6 +10502,7 @@ "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -10475,6 +10718,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-tsconfig": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.11.0.tgz", + "integrity": "sha512-sNsqf7XKQ38IawiVGPOoAlqZo1DMrO7TU+ZcZwi7yLl7/7S0JwmoBMKz/IkUPhSoXM0Ng3vT0yB1iCe5XavDeQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/get-uri": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", @@ -11118,6 +11374,19 @@ "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/index-to-position": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-0.1.2.tgz", @@ -11586,6 +11855,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-builtin-module": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-5.0.0.tgz", + "integrity": "sha512-f4RqJKBUe5rQkJ2eJEJBXSticB3hGbN9j0yxxMQFqIW89Jp9WYFtzfTcRlstDKVUTRzSOTLKRfO9vIztenwtxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-modules": "^5.0.0" + }, + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -11868,15 +12153,6 @@ "node": ">=8" } }, - "node_modules/is-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz", - "integrity": "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", @@ -12475,6 +12751,26 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "node_modules/json-stable-stringify": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz", + "integrity": "sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -12514,6 +12810,16 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true, + "license": "Public Domain", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -12618,6 +12924,16 @@ "node": ">=0.10.0" } }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, "node_modules/kruptein": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/kruptein/-/kruptein-2.2.3.tgz", @@ -13548,12 +13864,6 @@ "node": ">=10" } }, - "node_modules/module-not-found-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz", - "integrity": "sha512-pEk4ECWQXV6z2zjhRZUongnLJNUeGQJ3w6OQ5ctGwD+i5o93qjRQUk2Rt6VdNeu3sEP0AB4LcfvdebpxBRVr4g==", - "dev": true - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -13923,9 +14233,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", + "version": "2.0.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.23.tgz", + "integrity": "sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==", "dev": true, "license": "MIT" }, @@ -14904,6 +15214,199 @@ "node": ">= 0.8" } }, + "node_modules/patch-package": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.1.tgz", + "integrity": "sha512-VsKRIA8f5uqHQ7NGhwIna6Bx6D9s/1iXlA1hthBVBEbkq+t4kXD0HHt+rJhf/Z+Ci0F/HCB2hvn0qLdLG+Qxlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "ci-info": "^3.7.0", + "cross-spawn": "^7.0.3", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^10.0.0", + "json-stable-stringify": "^1.0.2", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "semver": "^7.5.3", + "slash": "^2.0.0", + "tmp": "^0.2.4", + "yaml": "^2.2.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=14", + "npm": ">5" + } + }, + "node_modules/patch-package/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/patch-package/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/patch-package/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/patch-package/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/patch-package/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/patch-package/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/patch-package/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/patch-package/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/patch-package/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/patch-package/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/patch-package/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/patch-package/node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, "node_modules/path-browserify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", @@ -15147,6 +15650,16 @@ "node": ">=4" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -15408,17 +15921,6 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, - "node_modules/proxyquire": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-2.1.3.tgz", - "integrity": "sha512-BQWfCqYM+QINd+yawJz23tbBM40VIGXOdDw3X344KcclI/gtBbdWF6SlQ4nK/bYhF9d27KYug9WzljHC6B9Ysg==", - "dev": true, - "dependencies": { - "fill-keys": "^1.0.2", - "module-not-found-error": "^1.0.1", - "resolve": "^1.11.1" - } - }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", @@ -15513,11 +16015,6 @@ } ] }, - "node_modules/queue-tick": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" - }, "node_modules/random-bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", @@ -15896,6 +16393,16 @@ "@babel/runtime": "^7.8.4" } }, + "node_modules/regexp-tree": { + "version": "0.1.27", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz", + "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==", + "dev": true, + "license": "MIT", + "bin": { + "regexp-tree": "bin/regexp-tree" + } + }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -16533,18 +17040,22 @@ } }, "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", + "is-core-module": "^2.16.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -16563,6 +17074,16 @@ "integrity": "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==", "dev": true }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/responselike": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", @@ -17443,6 +17964,16 @@ "node": ">=8" } }, + "node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -17757,16 +18288,14 @@ } }, "node_modules/streamx": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", - "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz", + "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==", + "license": "MIT", "dependencies": { + "events-universal": "^1.0.0", "fast-fifo": "^1.3.2", - "queue-tick": "^1.0.1", "text-decoder": "^1.1.0" - }, - "optionalDependencies": { - "bare-events": "^2.2.0" } }, "node_modules/string_decoder": { @@ -18632,6 +19161,26 @@ "node": ">=0.6.x" } }, + "node_modules/tsx": { + "version": "4.20.6", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz", + "integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.25.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -18997,9 +19546,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, "funding": [ { @@ -19018,7 +19567,7 @@ "license": "MIT", "dependencies": { "escalade": "^3.2.0", - "picocolors": "^1.1.0" + "picocolors": "^1.1.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -20593,6 +21142,19 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "devOptional": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/yargonaut": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/yargonaut/-/yargonaut-1.1.4.tgz", @@ -20815,22 +21377,22 @@ } }, "node_modules/zwave-js": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/zwave-js/-/zwave-js-15.15.0.tgz", - "integrity": "sha512-0GeFIOyGl2GhjN1xJJymTJqVpddk9nYGtTCQgc0kO+Zx3UlI4EWf2STREgFhLBolYI6tD3Kh3sFN89Gahux6gg==", + "version": "15.15.1", + "resolved": "https://registry.npmjs.org/zwave-js/-/zwave-js-15.15.1.tgz", + "integrity": "sha512-gAowBTMJ3jQl/+ER83Jpx5f37vUJ70ygCO0/DxKvADn4KZ2R/pHNh1a3INLmrg4pZeRCcb2P2ls+q4SzynQDPA==", "license": "MIT", "dependencies": { - "@alcalzone/jsonl-db": "^3.1.1", + "@alcalzone/jsonl-db": "^4.0.0", "@andrewbranch/untar.js": "^1.0.3", "@homebridge/ciao": "^1.3.4", - "@zwave-js/cc": "15.15.0", - "@zwave-js/config": "15.15.0", - "@zwave-js/core": "15.15.0", - "@zwave-js/host": "15.15.0", - "@zwave-js/nvmedit": "15.15.0", - "@zwave-js/serial": "15.15.0", - "@zwave-js/shared": "15.13.0", - "@zwave-js/testing": "15.15.0", + "@zwave-js/cc": "15.15.1", + "@zwave-js/config": "15.15.1", + "@zwave-js/core": "15.15.1", + "@zwave-js/host": "15.15.1", + "@zwave-js/nvmedit": "15.15.1", + "@zwave-js/serial": "15.15.1", + "@zwave-js/shared": "15.15.1", + "@zwave-js/testing": "15.15.1", "@zwave-js/waddle": "^1.2.1", "alcalzone-shared": "^5.0.0", "ansi-colors": "^4.1.3", @@ -20839,7 +21401,7 @@ "p-queue": "^8.1.0", "pathe": "^2.0.3", "reflect-metadata": "^0.2.2", - "semver": "^7.6.3", + "semver": "^7.7.2", "serialport": "^13.0.0", "source-map-support": "^0.5.21", "winston": "^3.17.0" @@ -20854,13 +21416,29 @@ "url": "https://github.com/sponsors/AlCalzone/" } }, - "node_modules/zwave-js/node_modules/alcalzone-shared": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/alcalzone-shared/-/alcalzone-shared-5.0.0.tgz", - "integrity": "sha512-X73hgVWcrIKUUB6jZgHj5flRbTft8AAoJ2MqRKEcAX1whW3OeGkxsQ6ol4nd4/rKxd1eoCRXUGW3cIhXrXU4Sg==", + "node_modules/zwave-js/node_modules/@alcalzone/jsonl-db": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@alcalzone/jsonl-db/-/jsonl-db-4.0.0.tgz", + "integrity": "sha512-UWLyq9FcNd+4Gv0bmy4F4v7ZOjn9LWY/VErS0xFWpKNmBb6ZuTCuWns9n60KIpaQN67UCXoVYMKNRseKC2adRg==", "license": "MIT", + "dependencies": { + "@alcalzone/proper-lockfile": "^4.1.3-0", + "alcalzone-shared": "^5.0.0" + }, "engines": { - "node": ">=18" + "node": ">=22" + } + }, + "node_modules/zwave-js/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/zxing-wasm": { diff --git a/package.json b/package.json index 11bf2d929e1..7377e0e6110 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,6 @@ { "name": "zwave-js-ui", + "type": "module", "version": "11.4.1", "description": "Z-Wave Control Panel and MQTT Gateway", "keywords": [ @@ -25,10 +26,11 @@ "author": "Daniel Lando ", "bin": "server/bin/www.js", "scripts": { + "postinstall": "patch-package", "dev": "vite", "dev-https": "SERVER_SSL='true' npm run dev", "dev:server": "nodemon", - "server": "node -r ./esbuild-register.js api/bin/www.ts", + "server": "node --experimental-transform-types api/bin/www.ts", "fake-stick": "npx mock-server -- -c server_config.js", "start": "node --preserve-symlinks server/bin/www.js", "bundle": "node esbuild.js", @@ -39,10 +41,10 @@ "lint:markdownlint": "markdownlint '**/*.md'", "lint-fix:markdownlint": "markdownlint --fix '**/*.md'", "test": "npm-run-all 'test:*'", - "test:server": "mocha --no-experimental-strip-types -r ./esbuild-register.js './test/**/*.test.ts'", + "test:server": "tsx node_modules/.bin/mocha test/**/*.test.ts", "test:ui": "mocha -r @babel/register src/**/*.test.js", "docs": "docsify serve ./docs", - "docs:generate": "node -r ./esbuild-register.js genereteDocs.ts", + "docs:generate": "node --experimental-transform-types generateDocs.ts", "coverage": "c8 --clean npm run test", "record-coverage": "c8 report --reporter=text-lcov --all --exclude='test/*' --exclude=.git --exclude=.eslintrc.js --exclude=.postcssrc.js --exclude=wallaby.js > ./coverage/lcov.info", "build": "npm-run-all build:*", @@ -85,7 +87,6 @@ "express-rate-limit": "^7.3.1", "express-session": "^1.18.0", "extract-zip": "^2.0.1", - "fs-extra": "^11.2.0", "js-logger": "^1.6.1", "jsonfile": "^6.1.0", "jsonwebtoken": "^9.0.2", @@ -115,7 +116,7 @@ "vuetify-sonner": "^0.3.0", "winston": "^3.13.0", "winston-daily-rotate-file": "^5.0.0", - "zwave-js": "^15.15.0", + "zwave-js": "^15.15.1", "zxing-wasm": "^1.2.15" }, "devDependencies": { @@ -134,19 +135,17 @@ "@types/express-rate-limit": "^5.1.3", "@types/express-session": "1.18.0", "@types/extract-zip": "^2.0.1", - "@types/fs-extra": "^11.0.4", "@types/jsonfile": "^6.1.4", "@types/jsonwebtoken": "^9.0.6", "@types/mocha": "^10.0.6", "@types/morgan": "^1.9.9", "@types/multer": "^1.4.11", "@types/node": "^20.14.6", - "@types/proxyquire": "^1.3.31", "@types/sinon-chai": "^3.2.12", "@typescript-eslint/eslint-plugin": "^8.45.0", "@typescript-eslint/parser": "^8.45.0", "@vitejs/plugin-vue": "^5.2.0", - "@yao-pkg/pkg": "^6.1.1", + "@yao-pkg/pkg": "^6.8.0", "c8": "^10.1.2", "chai": "^4.4.1", "chai-as-promised": "^8.0.0", @@ -154,7 +153,6 @@ "docsify": "^4.13.1", "docsify-cli": "^4.4.4", "esbuild": "^0.25.1", - "esbuild-register": "^3.5.0", "eslint": "^9.37.0", "eslint-config-prettier": "^10.1.8", "eslint-plugin-babel": "^5.3.1", @@ -162,16 +160,18 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^5.5.4", "eslint-plugin-promise": "^7.2.1", + "eslint-plugin-unicorn": "^61.0.2", "eslint-plugin-vue": "^9.26.0", "eslint-plugin-vuetify": "^2.5.3", + "esmock": "^2.7.3", "globals": "^16.4.0", "markdownlint-cli": "^0.41.0", "material-design-icons-iconfont": "^6.7.0", "mocha": "^10.4.0", "nodemon": "^3.1.3", "npm-run-all": "^4.1.5", + "patch-package": "^8.0.1", "prettier": "^3.3.2", - "proxyquire": "^2.1.3", "release-it": "^17.3.0", "rimraf": "^5.0.7", "sass": "1.77.6", @@ -180,6 +180,7 @@ "sinon-chai": "^3.7.0", "ts-morph": "^20.0.0", "ts-node": "^10.9.2", + "tsx": "^4.20.6", "typescript": "^5.9.3", "vite": "^6.0.0", "vite-plugin-pwa": "^0.21.0", diff --git a/package.sh b/package.sh index 0961dd18611..f0bf3e3c4e9 100755 --- a/package.sh +++ b/package.sh @@ -33,11 +33,6 @@ ask() { done } -pkg() { - echo "Executing command: npx pkg $@" - npx pkg $@ -} - APP=$(node -p "require('./package.json').name") PKG_FOLDER="pkg" @@ -59,6 +54,11 @@ else ARCH=$(uname -m) fi +pack() { + echo executing: pkg . --out-path $PKG_FOLDER --options experimental-require-module -t $1 $2 + npx pkg . --out-path $PKG_FOLDER --options experimental-require-module -t $1 $2 +} + echo "## Architecture: $ARCH" if [ ! -z "$1" ]; then @@ -82,11 +82,11 @@ if [ ! -z "$1" ]; then fi if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then - pkg package.json -t node$NODE_MAJOR-linux-arm64 --out-path $PKG_FOLDER + pack node$NODE_MAJOR-linux-arm64 elif [ "$ARCH" = "armv7" ]; then - pkg package.json -t node$NODE_MAJOR-linux-armv7 --out-path $PKG_FOLDER --public-packages=* + pack node$NODE_MAJOR-linux-armv7 --public-packages=* else - pkg package.json -t node$NODE_MAJOR-linux-x64,node$NODE_MAJOR-win-x64 --out-path $PKG_FOLDER + pack node$NODE_MAJOR-linux-x64,node$NODE_MAJOR-win-x64 fi else @@ -115,32 +115,32 @@ else case "$REPLY" in 1) echo "## Creating application package in $PKG_FOLDER folder" - pkg package.json -t node$NODE_MAJOR-linux-x64 --out-path $PKG_FOLDER + pack node$NODE_MAJOR-linux-x64 break ;; 2) echo "## Creating application package in $PKG_FOLDER folder" - pkg package.json -t node$NODE_MAJOR-linux-armv7 --out-path $PKG_FOLDER --public-packages=* + pack node$NODE_MAJOR-linux-armv7 --public-packages=* break ;; 3) echo "## Creating application package in $PKG_FOLDER folder" - pkg package.json -t node$NODE_MAJOR-linux-armv6 --out-path $PKG_FOLDER --public-packages=* + pack node$NODE_MAJOR-linux-armv6 --public-packages=* break ;; 4) echo "## Creating application package in $PKG_FOLDER folder" - pkg package.json -t node$NODE_MAJOR-linux-x86 --out-path $PKG_FOLDER + pack node$NODE_MAJOR-linux-x86 break ;; 5) echo "## Creating application package in $PKG_FOLDER folder" - pkg package.json -t node$NODE_MAJOR-alpine-x64 --out-path $PKG_FOLDER + pack node$NODE_MAJOR-alpine-x64 break ;; 6) echo "## Creating application package in $PKG_FOLDER folder" - pkg package.json -t node$NODE_MAJOR-linux-arm64 --out-path $PKG_FOLDER --public-packages=* + pack node$NODE_MAJOR-linux-arm64 --public-packages=* break ;; *) diff --git a/patches/native-url+0.3.4.patch b/patches/native-url+0.3.4.patch new file mode 100644 index 00000000000..b81c85e714a --- /dev/null +++ b/patches/native-url+0.3.4.patch @@ -0,0 +1,11 @@ +diff --git a/node_modules/native-url/third_party/url.d.ts b/node_modules/native-url/third_party/url.d.ts +index ced41a3..b745f83 100644 +--- a/node_modules/native-url/third_party/url.d.ts ++++ b/node_modules/native-url/third_party/url.d.ts +@@ -141,3 +141,5 @@ declare module 'url' { + [Symbol.iterator](): IterableIterator<[string, string]>; + } + } ++ ++export default url; +\ No newline at end of file diff --git a/server_config.js b/server_config.js index b5bb186e42a..e6c759ac759 100644 --- a/server_config.js +++ b/server_config.js @@ -1,8 +1,8 @@ // @ts-check -const { CommandClasses } = require('@zwave-js/core') -const { ccCaps } = require('@zwave-js/testing') +import { CommandClasses } from '@zwave-js/core' +import { ccCaps } from '@zwave-js/testing' -module.exports.default = { +export default { nodes: [ { id: 2, diff --git a/src/lib/SocketEvents.js b/src/lib/SocketEvents.js deleted file mode 100644 index 4e84f053ed0..00000000000 --- a/src/lib/SocketEvents.js +++ /dev/null @@ -1,34 +0,0 @@ -export const socketEvents = Object.freeze({ - init: 'INIT', // automatically sent when a new client connects to the socket - controller: 'CONTROLLER_CMD', // controller status updates - connected: 'CONNECTED', // socket status - nodeFound: 'NODE_FOUND', - nodeAdded: 'NODE_ADDED', - nodeRemoved: 'NODE_REMOVED', - nodeUpdated: 'NODE_UPDATED', - valueUpdated: 'VALUE_UPDATED', - valueRemoved: 'VALUE_REMOVED', - metadataUpdated: 'METADATA_UPDATED', - rebuildRoutesProgress: 'REBUILD_ROUTES_PROGRESS', - healthCheckProgress: 'HEALTH_CHECK_PROGRESS', - info: 'INFO', - api: 'API_RETURN', // api results - debug: 'DEBUG', - statistics: 'STATISTICS', - nodeEvent: 'NODE_EVENT', - grantSecurityClasses: 'GRANT_SECURITY_CLASSES', - validateDSK: 'VALIDATE_DSK', - inclusionAborted: 'INCLUSION_ABORTED', - znifferFrame: 'ZNIFFER_FRAME', - znifferState: 'ZNIFFER_STATE', - linkReliability: 'LINK_RELIABILITY', - otwFirmwareUpdate: 'OTW_FIRMWARE_UPDATE', -}) -// events from client ---> server -export const inboundEvents = Object.freeze({ - init: 'INITED', // get all nodes - zwave: 'ZWAVE_API', // call a zwave api - hass: 'HASS_API', // call an hass api - mqtt: 'MQTT_API', // call an mqtt api - zniffer: 'ZNIFFER_API', // call a zniffer api -}) diff --git a/src/lib/shared.js b/src/lib/shared.js deleted file mode 100644 index 27e8e1bb74d..00000000000 --- a/src/lib/shared.js +++ /dev/null @@ -1,9 +0,0 @@ -import { RFRegion } from 'zwave-js' -export function regionSupportsAutoPowerlevel(region) { - return ( - region === RFRegion.Europe || - region === RFRegion['Europe (Long Range)'] || - region === RFRegion.USA || - region === RFRegion['USA (Long Range)'] - ) -} diff --git a/test/lib/Constants.test.ts b/test/lib/Constants.test.ts index a096993a706..ce0bc136cce 100644 --- a/test/lib/Constants.test.ts +++ b/test/lib/Constants.test.ts @@ -6,7 +6,7 @@ import sinonChai from 'sinon-chai' chai.use(sinonChai) -import * as mod from '../../api/lib/Constants' +import * as mod from '../../api/lib/Constants.ts' describe('#Constants', () => { describe('#productionType()', () => { diff --git a/test/lib/Gateway.test.ts b/test/lib/Gateway.test.ts index 958c2996d03..4fa317c62ea 100644 --- a/test/lib/Gateway.test.ts +++ b/test/lib/Gateway.test.ts @@ -1,6 +1,6 @@ import chai, { expect } from 'chai' -import Gateway, { closeWatchers } from '../../api/lib/Gateway' -import { ZUINode } from '../../api/lib/ZwaveClient' +import Gateway, { closeWatchers } from '../../api/lib/Gateway.ts' +import type { ZUINode } from '../../api/lib/ZwaveClient.ts' import sinonChai from 'sinon-chai' chai.use(sinonChai) diff --git a/test/lib/jsonStore.test.ts b/test/lib/jsonStore.test.ts index 5205a1bf043..48d7fbb4364 100644 --- a/test/lib/jsonStore.test.ts +++ b/test/lib/jsonStore.test.ts @@ -1,8 +1,7 @@ import chai, { expect } from 'chai' -import proxyquire from 'proxyquire' -import { StorageHelper } from '../../api/lib/jsonStore' +import { StorageHelper } from '../../api/lib/jsonStore.ts' import sinon from 'sinon' -import { StoreFile, StoreKeys } from '../../api/config/store' +import type { StoreFile, StoreKeys } from '../../api/config/store.ts' import sinonChai from 'sinon-chai' import chaiAsPromised from 'chai-as-promised' @@ -14,15 +13,10 @@ describe('#jsonStore', () => { const config = { file: 'foo', default: { foo: 'defaultbar' } } it("doesn't throw error", () => { - const mod: StorageHelper = proxyquire( - '../../api/lib/jsonStore.ts', - { - jsonfile: { - readFile: sinon.stub().rejects(Error('FOO')), - }, - }, - ).default - return expect(mod['_getFile'](config)).to.not.be.rejected + const mod = new StorageHelper({ + readFile: sinon.stub().rejects(Error('FOO')) as any, + }) + return expect(mod._getFile(config)).to.not.be.rejected }) it('data returned', () => { @@ -30,46 +24,31 @@ describe('#jsonStore', () => { file: 'foo', data: { bar: 'mybar', a: 'a', b: 'c' }, } - const mod: StorageHelper = proxyquire( - '../../api/lib/jsonStore.ts', - { - jsonfile: { - readFile: sinon.stub().resolves(toReturn.data), - }, - }, - ).default - - return expect(mod['_getFile'](config)).to.eventually.deep.equal({ + const mod = new StorageHelper({ + readFile: sinon.stub().resolves(toReturn.data) as any, + }) + + return expect(mod._getFile(config)).to.eventually.deep.equal({ file: toReturn.file, data: { ...toReturn.data, ...config.default }, }) }) it('no data, return default', () => { - const mod: StorageHelper = proxyquire( - '../../api/lib/jsonStore.ts', - { - jsonfile: { - readFile: sinon.stub().resolves(null), - }, - }, - ).default - return expect(mod['_getFile'](config)).to.eventually.deep.equal({ + const mod = new StorageHelper({ + readFile: sinon.stub().resolves(null) as any, + }) + return expect(mod._getFile(config)).to.eventually.deep.equal({ file: 'foo', data: config.default, }) }) it('file not found, return default', () => { - const mod: StorageHelper = proxyquire( - '../../api/lib/jsonStore.ts', - { - jsonfile: { - readFile: sinon.stub().rejects({ code: 'ENOENT' }), - }, - }, - ).default - return expect(mod['_getFile'](config)).to.eventually.deep.equal({ + const mod = new StorageHelper({ + readFile: sinon.stub().rejects({ code: 'ENOENT' }) as any, + }) + return expect(mod._getFile(config)).to.eventually.deep.equal({ file: 'foo', data: config.default, }) @@ -88,14 +67,9 @@ describe('#jsonStore', () => { describe('#init()', () => { it('ok', async () => { const data = { foo: 'bar' } - const mod: StorageHelper = proxyquire( - '../../api/lib/jsonStore.ts', - { - jsonfile: { - readFile: sinon.stub().resolves(data), - }, - }, - ).default + const mod = new StorageHelper({ + readFile: sinon.stub().resolves(data) as any, + }) await mod.init(fakeStore) @@ -105,14 +79,9 @@ describe('#jsonStore', () => { }) it('error', async () => { - const mod: StorageHelper = proxyquire( - '../../api/lib/jsonStore.ts', - { - jsonfile: { - readFile: sinon.stub().rejects(Error('foo')), - }, - }, - ).default + const mod = new StorageHelper({ + readFile: sinon.stub().rejects(Error('foo')) as any, + }) await mod.init(fakeStore) @@ -123,14 +92,9 @@ describe('#jsonStore', () => { }) describe('#get()', () => { - const mod: StorageHelper = proxyquire( - '../../api/lib/jsonStore.ts', - { - jsonfile: { - readFile: sinon.stub().resolves('bar'), - }, - }, - ).default + const mod = new StorageHelper({ + readFile: sinon.stub().resolves('bar') as any, + }) beforeEach(async () => await mod.init(fakeStore)) @@ -142,7 +106,7 @@ describe('#jsonStore', () => { try { mod.get({ file: 'unknown' } as StoreFile) } catch (error) { - return expect(error.message).to.equal( + return expect((error as Error).message).to.equal( 'Requested file not present in store: unknown', ) } @@ -151,28 +115,18 @@ describe('#jsonStore', () => { describe('#put()', () => { it('ok', () => { - const mod: StorageHelper = proxyquire( - '../../api/lib/jsonStore.ts', - { - jsonfile: { - writeFile: sinon.stub().resolves('bar'), - }, - }, - ).default + const mod = new StorageHelper({ + writeFile: sinon.stub().resolves('bar') as any, + }) return expect( mod.put({ file: 'foo' } as StoreFile, 'bardata'), ).to.eventually.equal('bardata') }) it('error', () => { - const mod: StorageHelper = proxyquire( - '../../api/lib/jsonStore.ts', - { - jsonfile: { - writeFile: sinon.stub().rejects(Error('foo')), - }, - }, - ).default + const mod = new StorageHelper({ + writeFile: sinon.stub().rejects(Error('foo')) as any, + }) return expect( mod.put({ file: 'foo' } as StoreFile, ''), diff --git a/test/lib/logger.test.ts b/test/lib/logger.test.ts index 394e2b46032..4422465805b 100644 --- a/test/lib/logger.test.ts +++ b/test/lib/logger.test.ts @@ -1,15 +1,15 @@ import { expect } from 'chai' -import * as utils from '../../api/lib/utils' -import { logsDir } from '../../api/config/app' +import * as utils from '../../api/lib/utils.ts' +import { logsDir } from '../../api/config/app.ts' +import type { ModuleLogger } from '../../api/lib/logger.ts' import { customTransports, defaultLogFile, - ModuleLogger, sanitizedConfig, module, setupAll, stopCleanJob, -} from '../../api/lib/logger' +} from '../../api/lib/logger.ts' import winston from 'winston' function checkConfigDefaults(mod, cfg) { diff --git a/test/lib/utils.test.ts b/test/lib/utils.test.ts index 88c90ed10c5..b34b3cc22b3 100644 --- a/test/lib/utils.test.ts +++ b/test/lib/utils.test.ts @@ -1,6 +1,7 @@ import chai, { expect } from 'chai' -import proxyquire from 'proxyquire' -import sinon, { SinonStub } from 'sinon' +import esmock from 'esmock' +import type { SinonStub } from 'sinon' +import sinon from 'sinon' import sinonChai from 'sinon-chai' @@ -13,10 +14,15 @@ const snapshotPath = '/snapshot/zui' describe('#utils', () => { describe('#getPath()', () => { - const utils = proxyquire('../../api/lib/utils', { - path: { - resolve: () => snapshotPath, - }, + let utils: any + + before(async () => { + utils = await esmock('../../api/lib/utils.ts', { + path: { + resolve: () => snapshotPath, + join: (...args: string[]) => args.join('/'), + }, + }) }) it('write && process.pkg', () => { @@ -38,27 +44,30 @@ describe('#utils', () => { }) describe('#joinPath()', () => { - let path: { join: SinonStub; resolve: () => string } - let utils + let pathMock: { join: SinonStub; resolve: () => string } + let utils: any - before(() => { - path = { join: sinon.stub(), resolve: () => snapshotPath } - utils = proxyquire('../../api/lib/utils', { - path: path, + before(async () => { + pathMock = { + join: sinon.stub(), + resolve: () => snapshotPath, + } + utils = await esmock('../../api/lib/utils.ts', { + path: pathMock, }) }) it('zero length', () => { utils.joinPath() - return expect(path.join.callCount).to.equal(1) + return expect(pathMock.join.callCount).to.equal(1) }) it('1 length', () => { utils.joinPath('foo') - return expect(path.join).to.have.been.calledWith('foo') + return expect(pathMock.join).to.have.been.calledWith('foo') }) it('first arg bool gets new path 0', () => { utils.joinPath(true, 'bar') - return expect(path.join).to.have.been.calledWithExactly( + return expect(pathMock.join).to.have.been.calledWithExactly( snapshotPath, 'bar', ) diff --git a/tsconfig.json b/tsconfig.json index 3878b4db4b0..a64ce8bcffe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,26 @@ { "extends": "@tsconfig/node22/tsconfig.json", "compilerOptions": { + // Module settings for ESM output + "module": "esnext", + "moduleResolution": "bundler", + "target": "esnext", + // Necessary to support yarn portals with the node-modules linker, used by yarn link (berry) "preserveSymlinks": true, "resolveJsonModule": true, + + // Automatically rewrite import extensions from .ts to .js + "rewriteRelativeImportExtensions": true, + + // Output directory "outDir": "server", - + + // ESM compatibility + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + // TODO: Turn this on and fix all the errors "strict": false }, diff --git a/vite.config.mjs b/vite.config.mjs index baeea816726..7f7db7037fc 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -125,7 +125,7 @@ export default defineConfig(({ mode }) => { }, { find: /^@server\/(.+)/, - replacement: `${path.resolve(__dirname, 'src')}/$1`, + replacement: `${path.resolve(__dirname, 'server')}/$1`, }, ], preserveSymlinks: true,