npmのバージョンエラーと本家npmへの移行

今回はおま環なお話。

iPadから照明をコントロールするため、Raspberry Pi Zero Wと4chリレーや、ESP easy化したSONOFFを壁の中に埋め込み、GPIOを使って壁のスイッチからも、iPadのHomeからも、AndroidやWebページ上のHomeAssistatからも操作できるようにしています。

gentoolinux.hatenablog.com

gentoolinux.hatenablog.com

gentoolinux.hatenablog.com

リビングの照明はRaspberry Pi Zero Wでコントロールしていますが、それらのデバイスを司り、Homeアプリに中継するHomebrigeというミドルウェアは、Gentoo Linuxサーバーに設定しています。
先日、何気なくGentoo Linuxにインストールされているソフトウェアをバージョンアップすべく、emerge -uDN @worldを実行したところ、いつになく呆気なく、500以上のパッケージがノーエラーでバージョンアップできました。
そこで、再起動をかけたところ、なんだかcron.hourlyが毎時間エラーレポートをメールで送信してきています。
cron.hourlyには、homebridgeのプロセスに異常があった場合、再起動するように仕掛けてます。(それくらい不安定だった。)
が、どうやらnode.jsがバージョンアップされたためにエラーが起きていたらしいのです。

homebridge porosess is not found.
Starting homebridge

/usr/local/lib/node_modules/homebridge/lib/logger.js:9
const chalk_1 = __importDefault(require("chalk"));
                                ^
Error [ERR_REQUIRE_ESM]: require() of ES Module /usr/local/lib/node_modules/homebridge/node_modules/chalk/source/index.js from /usr/local/lib/node_modules/homebridge/lib/logger.js not supported.
Instead change the require of index.js in /usr/local/lib/node_modules/homebridge/lib/logger.js to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (/usr/local/lib/node_modules/homebridge/lib/logger.js:9:33)

そこで、これらを解消しようと、まずnpmでhomebridgeをアップデートしようとしました。

gentoo / # npm update homebridge
npm WARN npm npm does not support Node.js v20.11.0
npm WARN npm You should probably upgrade to a newer version of node as we
npm WARN npm can't make any promises that npm will work with this version.
npm WARN npm Supported releases of Node.js are the latest release of 4, 6, 7, 8.
npm WARN npm You can find the latest version at https://nodejs.org/
npm ERR! cb.apply is not a function

npm ERR! A complete log of this run can be found in:
npm ERR!     /root/.npm/_logs/2024-02-27T14_26_31_191Z-debug.log

意訳すると「このnpmはNode.js v20.11.0をサポートしてないよ。node.jsをアップデートしないとダメだよ。このnpmはnode.jsのバージョン4,6,7,8をサポートしてるよ。」
って、ここに入っているnode.jsはgentooでは最新のv20なんですけど・・・。

そして、自分の所業を遡ると、こんなことが書いてました。

gentoolinux.hatenablog.com

これを読むと、「useフラグにnpmをつけてnodejsをemergeすると、勝手にnpmも入ってくるよ」と。
ということは、今使っているnpmは何らかの理由で(理由は忘れた)、オーバーレイインストールしたか、無理矢理手動インストールしたかのどちらかです。

npmはどこにあるのか?

gentoo / # npm -v
5.5.1
gentoo / # which npm
/usr/local/bin/npm
gentoo / # ls -al /usr/local/bin/npm
lrwxrwxrwx  1 root root       38 1114  2017 npm -> ../lib/node_modules/npm/bin/npm-cli.js

実態であるnpm-cli.jsのバージョンが古いんですね。しかも、/usr/local/libにインストールしているということは、公式リポジトリ以外からインストールしているっていうことですね。
npmをUSEフラグに記述しているので、node.jsのアップデート時に、最新のnpmがどこかにインストールされているはずです。

gentoo / # find / -name npm-cli.js
/var/tmp/portage/net-libs/nodejs-20.8.1/work/node-v20.8.1/deps/npm/bin/npm-cli.js
/var/tmp/portage/net-libs/nodejs-20.8.1/work/node-v20.8.1/deps/npm/test/bin/npm-cli.js
/var/tmp/portage/net-libs/nodejs-20.9.0/work/node-v20.9.0/deps/npm/bin/npm-cli.js
/var/tmp/portage/net-libs/nodejs-20.9.0/work/node-v20.9.0/deps/npm/test/bin/npm-cli.js
/usr/local/n/versions/node/8.9.1/lib/node_modules/npm/bin/npm-cli.js
/usr/local/n/versions/node/9.0.0/lib/node_modules/npm/bin/npm-cli.js
/usr/local/lib/node_modules/npm/bin/npm-cli.js
/usr/lib64/node_modules/npm/bin/npm-cli.js

gentoo / # /usr/lib64/node_modules/npm/bin/npm-cli.js -v
10.2.4

公式リポジトリ上のnpmは/usr/lib64/node_modules/npm/bin/npm-cli.jsにあるようです。
ということは、公式リポジトリからリンクされているnpm自体も、/usr/local/binではない場所にありそうです。

gentoo / #  find / -name npm
/etc/npm
/var/tmp/portage/net-libs/nodejs-20.8.1/work/node-v20.8.1/deps/corepack/shims/npm
/var/tmp/portage/net-libs/nodejs-20.8.1/work/node-v20.8.1/deps/corepack/shims/nodewin/npm
/var/tmp/portage/net-libs/nodejs-20.8.1/work/node-v20.8.1/deps/npm
/var/tmp/portage/net-libs/nodejs-20.8.1/work/node-v20.8.1/deps/npm/bin/npm
/var/tmp/portage/net-libs/nodejs-20.8.1/work/node-v20.8.1/tools/msvs/npm
/var/tmp/portage/net-libs/nodejs-20.8.1/work/node-v20.8.1/tools/macos-installer/pkgbuild/npm
/var/tmp/portage/net-libs/nodejs-20.9.0/work/node-v20.9.0/deps/corepack/shims/npm
/var/tmp/portage/net-libs/nodejs-20.9.0/work/node-v20.9.0/deps/corepack/shims/nodewin/npm
/var/tmp/portage/net-libs/nodejs-20.9.0/work/node-v20.9.0/deps/npm
/var/tmp/portage/net-libs/nodejs-20.9.0/work/node-v20.9.0/deps/npm/bin/npm
/var/tmp/portage/net-libs/nodejs-20.9.0/work/node-v20.9.0/tools/msvs/npm
/var/tmp/portage/net-libs/nodejs-20.9.0/work/node-v20.9.0/tools/macos-installer/pkgbuild/npm
/usr/local/n/versions/node/8.9.1/bin/npm
/usr/local/n/versions/node/8.9.1/lib/node_modules/npm
/usr/local/n/versions/node/8.9.1/lib/node_modules/npm/bin/npm
/usr/local/n/versions/node/9.0.0/bin/npm
/usr/local/n/versions/node/9.0.0/lib/node_modules/npm
/usr/local/n/versions/node/9.0.0/lib/node_modules/npm/bin/npm
/usr/local/bin/npm
/usr/local/lib/node_modules/npm
/usr/local/lib/node_modules/npm/bin/npm
/usr/lib64/node_modules/npm
/usr/lib64/node_modules/npm/bin/npm
/usr/bin/npm
/usr/share/bash-completion/completions/npm
/root/.npm/registry.npmjs.org/npm
/root/.npm/npm

gentoo / #  ls -al /usr/bin/npm
lrwxrwxrwx 1 root root 40  225 03:27 /usr/bin/npm -> ../lib64/node_modules/npm/bin/npm-cli.js

gentoo / # /usr/bin/npm -v
10.2.4

何のことはない、/usr/local/bin/npmを削除して、今後は/usr/bin/npmを使えば良いだけのことでした。

これでhomebridgeを起動してもエラーが起きます。

[2024/2/27 22:53:10] TypeError: Invalid initialization vector
    at Cipheriv.createCipherBase (node:internal/crypto/cipher:121:19)
    at Cipheriv.createCipherWithIV (node:internal/crypto/cipher:140:3)
    at new Cipheriv (node:internal/crypto/cipher:243:3)
    at Object.createCipheriv (node:crypto:146:10)
    at Object.chacha20_poly1305_encryptAndSeal (/usr/local/lib/node_modules/homebridge/node_modules/hap-nodejs/src/lib/util/hapCrypto.ts:90:25)
    at HAPServer._this._handlePairVerifyStepOne (/usr/local/lib/node_modules/homebridge/node_modules/hap-nodejs/src/lib/HAPServer.ts:553:33)
    at HAPServer._this._handlePairVerify (/usr/local/lib/node_modules/homebridge/node_modules/hap-nodejs/src/lib/HAPServer.ts:515:12)
    at IncomingMessage.<anonymous> (/usr/local/lib/node_modules/homebridge/node_modules/hap-nodejs/src/lib/HAPServer.ts:280:24)
    at IncomingMessage.emit (node:events:518:28)
    at endReadableNT (node:internal/streams/readable:1696:12)
[2024/2/27 22:53:10] Got SIGTERM, shutting down Homebridge...

まずは、関連モジュールをアップデートします。
アップデートにはnpm-check-updates(コマンドは頭文字を取ってncu)を使うと良いそうですので、npmでインストールし、ncu -uでアップデート情報をpackage.jsonに書き込み、npm installでpackage.jsonに書かれた情報から各パッケージをアップデートします。

gentoo / # npm install -g npm-check-updates
added 336 packages in 16s

67 packages are looking for funding
  run `npm fund` for details

gentoo / #  ncu -u
Upgrading /usr/local/lib/node_modules/homebridge/package.json
[====================] 20/20 100%

 @types/debug                        ^4.1.5  →   ^4.1.12
 @types/jest                       ^26.0.13  →  ^29.5.12
 @types/node                       10.17.2920.11.20
 @types/semver                       ^7.3.3  →    ^7.5.8
 @typescript-eslint/eslint-plugin    ^4.0.1  →    ^7.1.0
 @typescript-eslint/parser           ^4.0.1  →    ^7.1.0
 chalk                               ^4.1.0  →    ^5.3.0
 commander                            5.1.012.0.0
 eslint                              ^7.8.1  →   ^8.57.0
 eslint-plugin-jest                ^23.20.0  →   ^27.9.0
 hap-nodejs                         ^0.7.10  →   ^0.11.1
 jest                               ^26.4.2  →   ^29.7.0
 node-persist                       ^0.0.11  →    ^4.0.1
 rimraf                              ^3.0.2  →    ^5.0.5
 semver                              ^7.3.2  →    ^7.6.0
 source-map-support                 ^0.5.19  →   ^0.5.21
 ts-jest                            ^26.3.0  →   ^29.1.2
 ts-node                             ^9.0.0  →   ^10.9.2
 typescript                          ^4.0.2  →    ^5.3.3

Run npm install to install new versions.

gentoo / # npm install

added 546 packages, removed 11 packages, changed 58 packages, and audited 609 packages in 36s

116 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

そして最後に、肝心のhomebridgeそのものもアップデートしましょう。

gentoo / # npm install -g --unsafe-perm homebridge@latest

added 91 packages, removed 16 packages, and changed 14 packages in 2s

43 packages are looking for funding
  run `npm fund` for details

それでもエラーが出ます。

gentoo / # /etc/local.d/homebridge.start 
Starting homebridge

/usr/local/lib/node_modules/homebridge/lib/logger.js:9
const chalk_1 = __importDefault(require("chalk"));
                                ^
Error [ERR_REQUIRE_ESM]: require() of ES Module /usr/local/lib/node_modules/homebridge/node_modules/chalk/source/index.js from /usr/local/lib/node_modules/homebridge/lib/logger.js not supported.
Instead change the require of index.js in /usr/local/lib/node_modules/homebridge/lib/logger.js to a dynamic import() which is available in all CommonJS modules.
    at Object.<anonymous> (/usr/local/lib/node_modules/homebridge/lib/logger.js:9:33)

よく読むと、そもそもhomebridge自体も/usr/local/binにあるもののようです。
最新のhomegridgeはどこなのか?

gentoo / # find / -name homebridge
/var/homebridge
/usr/local/bin/homebridge
/usr/local/lib/node_modules/homebridge-http-switch/test/homebridge
/usr/local/lib/node_modules/homebridge
/usr/local/lib/node_modules/homebridge/bin/homebridge
/usr/lib64/node_modules/homebridge
/usr/lib64/node_modules/homebridge/bin/homebridge
/usr/bin/homebridge
/root/.npm/registry.npmjs.org/homebridge

やはり、/usr/bin/homebridgeがありましたね。

/etc/local.d/homebridge.startの内容を変更します。

#!/bin/sh


#dir="/var/homebridge"
name="homebridge"
pid_file="/var/run/$name.pid"
stdout_log="/var/log/$name.log"
stderr_log="/var/log/$name.err"

echo "Starting $name"
#cd "$dir"
/usr/bin/homebridge -U /var/homebridge &
echo $! > "$pid_file"

あと、node.js自体も、/usr/local/bin/nodeにシンボリックリンクあるので、/usr/local/bin/npmや/usr/local/bin/homebridgeと一緒に消しておきます。
(これらはシンボリックリンクなので、消しても実体は残っています。)

これで無事にhomebridgeが起動・復活しました。