zwave-js
Version:
Z-Wave driver written entirely in JavaScript/TypeScript
90 lines • 4.13 kB
JavaScript
import { untar } from "@andrewbranch/untar.js";
import { ZWaveError, ZWaveErrorCodes, gunzipSync } from "@zwave-js/core";
import { getErrorMessage, writeTextFile, } from "@zwave-js/shared";
import { isObject } from "alcalzone-shared/typeguards";
import path from "pathe";
import semverInc from "semver/functions/inc.js";
import semverValid from "semver/functions/valid.js";
import semverMaxSatisfying from "semver/ranges/max-satisfying.js";
/**
* Checks whether there is a compatible update for the currently installed config package.
* Returns the new version if there is an update, `undefined` otherwise.
* Throws if the update check failed.
*/
export async function checkForConfigUpdates(currentVersion) {
const { default: ky } = await import("ky");
let registry;
try {
registry = await ky
.get("https://registry.npmjs.org/@zwave-js/config")
.json();
}
catch {
throw new ZWaveError(`Could not check for config updates: Failed to download package information!`, ZWaveErrorCodes.Config_Update_RegistryError);
}
if (!isObject(registry) || !isObject(registry.versions)) {
throw new ZWaveError(`Could not check for config updates: Downloaded package information does not contain version information!`, ZWaveErrorCodes.Config_Update_RegistryError);
}
// Find the highest possible prepatch update (e.g. 7.2.4 -> 7.2.5-20200424)
const allVersions = Object.keys(registry.versions)
.filter((v) => !!semverValid(v))
.filter((v) => /-\d{8}$/.test(v));
const updateRange = `>${currentVersion} <${semverInc(currentVersion, "patch")}`;
const updateVersion = semverMaxSatisfying(allVersions, updateRange, {
includePrerelease: true,
});
if (updateVersion)
return updateVersion;
}
/**
* Downloads and installs the given configuration update.
* This only works if an external configuation directory is used.
*/
export async function installConfigUpdate(fs, newVersion, external) {
const { default: ky } = await import("ky");
let registryInfo;
try {
registryInfo = await ky
.get(`https://registry.npmjs.org/@zwave-js/config/${newVersion}`)
.json();
}
catch {
throw new ZWaveError(`Config update failed: Could not fetch package info from npm registry!`, ZWaveErrorCodes.Config_Update_InstallFailed);
}
const url = registryInfo?.dist?.tarball;
if (typeof url !== "string") {
throw new ZWaveError(`Config update failed: Could not fetch package tarball URL from npm registry!`, ZWaveErrorCodes.Config_Update_InstallFailed);
}
let tarballData;
try {
tarballData = new Uint8Array(await ky.get(url).arrayBuffer());
}
catch (e) {
throw new ZWaveError(`Config update failed: Could not download tarball. Reason: ${getErrorMessage(e)}`, ZWaveErrorCodes.Config_Update_InstallFailed);
}
try {
// Extract json files from the tarball's config directory
// and overwrite the external config directory with them
const tarFiles = untar(gunzipSync(tarballData).buffer);
await fs.deleteDir(external.configDir);
await fs.ensureDir(external.configDir);
const prefix = "package/config/";
for (const file of tarFiles) {
if (!file.filename.startsWith(prefix)
|| !file.filename.endsWith(".json")) {
continue;
}
const filename = file.filename.slice(prefix.length);
const targetFileName = path.join(external.configDir, filename);
const targetDirName = path.dirname(targetFileName);
await fs.ensureDir(targetDirName);
await fs.writeFile(targetFileName, new Uint8Array(file.fileData));
}
const externalVersionFilename = path.join(external.configDir, "version");
await writeTextFile(fs, externalVersionFilename, newVersion);
}
catch {
throw new ZWaveError(`Config update failed: Could not extract tarball`, ZWaveErrorCodes.Config_Update_InstallFailed);
}
}
//# sourceMappingURL=UpdateConfig.js.map