2025/9/21 Shai-Hulud対策としてsafe-chainをWindows11でインストール失敗!簡易検査スクリプトを作った!
はじめに
背景:Shai-Huludとは?
Shai-Huludは、複数の人気npmパッケージに感染し、インストール時に自動的に他のパッケージへ感染を広げる自己伝播型マルウェアです。CrowdStrikeやNativeScript関連のパッケージが多数含まれており、CI/CD環境や開発マシンへの影響が懸念されています。
2025年9月現在、npm のサプライチェーン攻撃対策として safe-chain を導入する動きが出ています。
safe-chain は npm / npx / yarn などのコマンドをラップして、マルウェアを含む依存関係を検知するツールです。
特に npm install 実行時に、インストール対象のパッケージやその依存関係を事前にスキャンし、Shai-Hulud のような既知の感染パッケージが含まれていないかをチェックします。
しかし、Windows 11 + PowerShell 環境で safe-chain setup
を実行するとメモリ不足エラーで落ちました。
ChatGptはじめいろいろ聞いたけど結局、インストールできませんでした。
そこで今回は、実際に遭遇したエラーと、それを手動で修正したが失敗した件。
さらに、代替の簡易的な方法としてPythonを使って感染報告のモジュールがpackage-lock.jsonに入っていないか調べる方法をご紹介します。
環境
- Windows 11Home 24H2
- Node.js v22.14.0
- npm v10 系
- PowerShell 5.1
Windows 11 + PowerShell で safe-chain インストール失敗の詳細
結局、失敗したので実行しないほうがいいかもしれません。問題なくできるかもしれませんが、もしうまくいかなかったときの参考にしてください。
インストール
まずはグローバルに safe-chain をインストールします。
npm install -g @aikidosec/safe-chain
ここまでは問題ありません。(結局、最終的にはアンインストールしました。)
safe-chain setup
での失敗
公式手順どおりに
safe-chain setup
を実行すると、次のようなエラーで失敗しました。
FATAL ERROR: invalid array length Allocation failed - JavaScript heap out of memory
原因は PowerShell の alias 設定を自動で書き込む処理がメモリ不足でクラッシュしている模様です。
Node.js のメモリ上限を8Gまで増やしてみましたがダメでした。
失敗した対策:PowerShell プロファイルに手動で関数を定義
そこで setup
は使わず、PowerShell のプロファイルに自分でラッパー関数を書く方法を取りました。
プロファイルファイルを開きます:
notepad $PROFILE
例:C:\Users\<ユーザー名>\OneDrive\ドキュメント\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
ファイル末尾に以下を追記します:
function npm { & "C:\Users\<ユーザー名>\AppData\Roaming\npm\safe-chain.ps1" npm @args }
⚠️
safe-chain.ps1
のパスは環境に合わせて修正してください。通常は
C:\Users\<ユーザー名>\AppData\Roaming\npm\safe-chain.ps1
にあります。
動作確認
PowerShell を再起動してから、次を実行します。
Get-Command npm
結果が Function
になっていれば OK。
次にテスト用パッケージをインストールします:
npm install safe-chain-test
結果
本来、危険と判定しインストールしないはずですが、
safe-chain が走らず、そのままインストールされました。
ということで、うまくいかなかった。
元に戻した
戻し方は以下の通りです。
npm uninstall -g @aikidosec/safe-chain
Microsoft.PowerShell_profile.ps1 に書いた safe-chain 関連の行は、コメントアウトまたは削除。
package-lock.json
の中にないか検査するPythonスクリプト
🛡️ 「Shai-Hulud」に感染報告されたモジュールがはじめに
Pythonで package-lock.json
の中に感染パッケージが入っていないか検査するスクリプトを作りました。
感染パッケージの一覧はこちらを参考にさせてもらいました。:Qiita記事
Pythonで感染チェックする方法
1. 感染パッケージリストの整形
Qiitaの記事の shaiHuludCompromisedPackages
はJavaScript形式なので、Python辞書に変換する必要があります。以下のスクリプトで変換できます:
import json
import re
# JavaScript形式の配列(Qiitaからコピペ、最後の,なし)
input_js = """
[
{ package: "@ahmedhfarag/ngx-perfect-scrollbar", versions: ["20.0.20"] },
{ package: "@ahmedhfarag/ngx-virtual-scroller", versions: ["4.0.4"] },
{ package: "@art-ws/common", versions: ["2.0.22"] },
{ package: "@art-ws/config-eslint", versions: ["2.0.4", "2.0.5"] },
{ package: "@art-ws/config-ts", versions: ["2.0.7", "2.0.8"] },
{ package: "@art-ws/db-context", versions: ["2.0.21"] },
{ package: "@art-ws/di", versions: ["2.0.28"] },
{ package: "@art-ws/di-node", versions: ["2.0.13"] },
{ package: "@art-ws/eslint", versions: ["1.0.5", "1.0.6"] },
{ package: "@art-ws/fastify-http-server", versions: ["2.0.24"] },
{ package: "@art-ws/http-server", versions: ["2.0.21"] },
{ package: "@art-ws/openapi", versions: ["0.1.9"] },
{ package: "@art-ws/package-base", versions: ["1.0.5", "1.0.6"] },
{ package: "@art-ws/prettier", versions: ["1.0.5", "1.0.6"] },
{ package: "@art-ws/slf", versions: ["2.0.15"] },
{ package: "@art-ws/ssl-info", versions: ["1.0.9", "1.0.10"] },
{ package: "@art-ws/web-app", versions: ["1.0.3", "1.0.4"] },
{ package: "@crowdstrike/commitlint", versions: ["8.1.1", "8.1.2"] },
{ package: "@crowdstrike/falcon-shoelace", versions: ["0.4.1"] },
{ package: "@crowdstrike/foundry-js", versions: ["0.19.1", "0.19.2"] },
{ package: "@crowdstrike/glide-core", versions: ["0.34.2", "0.34.3"] },
{ package: "@crowdstrike/logscale-dashboard", versions: ["1.205.1", "1.205.2"] },
{ package: "@crowdstrike/logscale-file-editor", versions: ["1.205.1", "1.205.2"] },
{ package: "@crowdstrike/logscale-parser-edit", versions: ["1.205.1", "1.205.2"] },
{ package: "@crowdstrike/logscale-search", versions: ["1.205.1", "1.205.2"] },
{ package: "@crowdstrike/tailwind-toucan-base", versions: ["5.0.1", "5.0.2"] },
{ package: "@ctrl/deluge", versions: ["7.2.1", "7.2.2"] },
{ package: "@ctrl/golang-template", versions: ["1.4.2", "1.4.3"] },
{ package: "@ctrl/magnet-link", versions: ["4.0.3", "4.0.4"] },
{ package: "@ctrl/ngx-codemirror", versions: ["7.0.1", "7.0.2"] },
{ package: "@ctrl/ngx-csv", versions: ["6.0.1", "6.0.2"] },
{ package: "@ctrl/ngx-emoji-mart", versions: ["9.2.1", "9.2.2"] },
{ package: "@ctrl/ngx-rightclick", versions: ["4.0.1", "4.0.2"] },
{ package: "@ctrl/qbittorrent", versions: ["9.7.1", "9.7.2"] },
{ package: "@ctrl/react-adsense", versions: ["2.0.1", "2.0.2"] },
{ package: "@ctrl/shared-torrent", versions: ["6.3.1", "6.3.2"] },
{ package: "@ctrl/tinycolor", versions: ["4.1.1", "4.1.2"] },
{ package: "@ctrl/torrent-file", versions: ["4.1.1", "4.1.2"] },
{ package: "@ctrl/transmission", versions: ["7.3.1"] },
{ package: "@ctrl/ts-base32", versions: ["4.0.1", "4.0.2"] },
{ package: "@hestjs/core", versions: ["0.2.1"] },
{ package: "@hestjs/cqrs", versions: ["0.1.6"] },
{ package: "@hestjs/demo", versions: ["0.1.2"] },
{ package: "@hestjs/eslint-config", versions: ["0.1.2"] },
{ package: "@hestjs/logger", versions: ["0.1.6"] },
{ package: "@hestjs/scalar", versions: ["0.1.7"] },
{ package: "@hestjs/validation", versions: ["0.1.6"] },
{ package: "@nativescript-community/arraybuffers", versions: ["1.1.6", "1.1.7", "1.1.8"] },
{ package: "@nativescript-community/gesturehandler", versions: ["2.0.35"] },
{ package: "@nativescript-community/perms", versions: ["3.0.5", "3.0.6", "3.0.7", "3.0.8"] },
{ package: "@nativescript-community/sqlite", versions: ["3.5.2", "3.5.3", "3.5.4", "3.5.5"] },
{ package: "@nativescript-community/text", versions: ["1.6.9", "1.6.10", "1.6.11", "1.6.12"] },
{ package: "@nativescript-community/typeorm", versions: ["0.2.30", "0.2.31", "0.2.32", "0.2.33"] },
{ package: "@nativescript-community/ui-collectionview", versions: ["6.0.6"] },
{ package: "@nativescript-community/ui-document-picker", versions: ["1.1.27", "1.1.28"] },
{ package: "@nativescript-community/ui-drawer", versions: ["0.1.30"] },
{ package: "@nativescript-community/ui-image", versions: ["4.5.6"] },
{ package: "@nativescript-community/ui-label", versions: ["1.3.35", "1.3.36", "1.3.37"] },
{ package: "@nativescript-community/ui-material-bottom-navigation", versions: ["7.2.72", "7.2.73", "7.2.74", "7.2.75"] },
{ package: "@nativescript-community/ui-material-bottomsheet", versions: ["7.2.72"] },
{ package: "@nativescript-community/ui-material-core", versions: ["7.2.72", "7.2.73", "7.2.74", "7.2.75"] },
{ package: "@nativescript-community/ui-material-core-tabs", versions: ["7.2.72", "7.2.73", "7.2.74", "7.2.75"] },
{ package: "@nativescript-community/ui-material-ripple", versions: ["7.2.72", "7.2.73", "7.2.74", "7.2.75"] },
{ package: "@nativescript-community/ui-material-tabs", versions: ["7.2.72", "7.2.73", "7.2.74", "7.2.75"] },
{ package: "@nativescript-community/ui-pager", versions: ["14.1.36", "14.1.37", "14.1.38"] },
{ package: "@nativescript-community/ui-pulltorefresh", versions: ["2.5.4", "2.5.5", "2.5.6", "2.5.7"] },
{ package: "@nexe/config-manager", versions: ["0.1.1"] },
{ package: "@nexe/eslint-config", versions: ["0.1.1"] },
{ package: "@nexe/logger", versions: ["0.1.3"] },
{ package: "@nstudio/angular", versions: ["20.0.4", "20.0.5", "20.0.6"] },
{ package: "@nstudio/focus", versions: ["20.0.4", "20.0.5", "20.0.6"] },
{ package: "@nstudio/nativescript-checkbox", versions: ["2.0.6", "2.0.7", "2.0.8", "2.0.9"] },
{ package: "@nstudio/nativescript-loading-indicator", versions: ["5.0.1", "5.0.2", "5.0.3", "5.0.4"] },
{ package: "@nstudio/ui-collectionview", versions: ["5.1.11", "5.1.12", "5.1.13", "5.1.14"] },
{ package: "@nstudio/web", versions: ["20.0.4"] },
{ package: "@nstudio/web-angular", versions: ["20.0.4"] },
{ package: "@nstudio/xplat", versions: ["20.0.5", "20.0.6", "20.0.7"] },
{ package: "@nstudio/xplat-utils", versions: ["20.0.5", "20.0.6", "20.0.7"] },
{ package: "@operato/board", versions: ["9.0.36", "9.0.37", "9.0.38", "9.0.39", "9.0.40", "9.0.41", "9.0.42", "9.0.43", "9.0.44", "9.0.45", "9.0.46"] },
{ package: "@operato/data-grist", versions: ["9.0.29", "9.0.35", "9.0.36", "9.0.37"] },
{ package: "@operato/graphql", versions: ["9.0.22", "9.0.35", "9.0.36", "9.0.37", "9.0.38", "9.0.39", "9.0.40", "9.0.41", "9.0.42", "9.0.43", "9.0.44", "9.0.45", "9.0.46"] },
{ package: "@operato/headroom", versions: ["9.0.2", "9.0.35", "9.0.36", "9.0.37"] },
{ package: "@operato/help", versions: ["9.0.35", "9.0.36", "9.0.37", "9.0.38", "9.0.39", "9.0.40", "9.0.41", "9.0.42", "9.0.43", "9.0.44", "9.0.45", "9.0.46"] },
{ package: "@operato/i18n", versions: ["9.0.35", "9.0.36", "9.0.37"] },
{ package: "@operato/input", versions: ["9.0.27", "9.0.35", "9.0.36", "9.0.37", "9.0.38", "9.0.39", "9.0.40", "9.0.41", "9.0.42", "9.0.43", "9.0.44", "9.0.45", "9.0.46"] },
{ package: "@operato/layout", versions: ["9.0.35", "9.0.36", "9.0.37"] },
{ package: "@operato/popup", versions: ["9.0.22", "9.0.35", "9.0.36", "9.0.37", "9.0.38", "9.0.39", "9.0.40", "9.0.41", "9.0.42", "9.0.43", "9.0.44", "9.0.45", "9.0.46"] },
{ package: "@operato/pull-to-refresh", versions: ["9.0.36", "9.0.37", "9.0.38", "9.0.39", "9.0.40", "9.0.41", "9.0.42"] },
{ package: "@operato/shell", versions: ["9.0.22", "9.0.35", "9.0.36", "9.0.37", "9.0.38", "9.0.39"] },
{ package: "@operato/styles", versions: ["9.0.2", "9.0.35", "9.0.36", "9.0.37"] },
{ package: "@operato/utils", versions: ["9.0.22", "9.0.35", "9.0.36", "9.0.37", "9.0.38", "9.0.39", "9.0.40", "9.0.41", "9.0.42", "9.0.43", "9.0.44", "9.0.45", "9.0.46"] },
{ package: "@teselagen/bounce-loader", versions: ["0.3.16", "0.3.17"] },
{ package: "@teselagen/liquibase-tools", versions: ["0.4.1"] },
{ package: "@teselagen/range-utils", versions: ["0.3.14", "0.3.15"] },
{ package: "@teselagen/react-list", versions: ["0.8.19", "0.8.20"] },
{ package: "@teselagen/react-table", versions: ["6.10.19"] },
{ package: "@thangved/callback-window", versions: ["1.1.4"] },
{ package: "@things-factory/attachment-base", versions: ["9.0.43", "9.0.44", "9.0.45", "9.0.46", "9.0.47", "9.0.48", "9.0.49", "9.0.50"] },
{ package: "@things-factory/auth-base", versions: ["9.0.43", "9.0.44", "9.0.45"] }
]
"""
import re
import json
def convert_js_array_to_python_dict(js_text):
# コメント行を削除
js_text = re.sub(r'//.*', '', js_text)
# const宣言やセミコロンを削除
js_text = re.sub(r'const\s+\w+\s*=\s*', '', js_text)
js_text = js_text.strip().rstrip(';')
# JavaScriptのキーをJSON形式に変換
js_text = re.sub(r'package\s*:', '"package":', js_text)
js_text = re.sub(r'versions\s*:', '"versions":', js_text)
# シングルクォートをダブルクォートに(必要なら)
js_text = js_text.replace("'", '"')
# 配列が [] で囲まれているか確認
if not js_text.startswith('['):
js_text = '[' + js_text
if not js_text.endswith(']'):
js_text = js_text + ']'
# JSONとして読み込む
try:
js_array = json.loads(js_text)
except json.JSONDecodeError as e:
print("❌ JSON変換に失敗しました:", e)
return {}
# Python辞書形式に変換
py_dict = {entry["package"]: entry["versions"] for entry in js_array}
return py_dict
if __name__ == "__main__":
# result = js_to_python_dict(input_js)
result = convert_js_array_to_python_dict(input_js)
print("Python形式の辞書:")
print(json.dumps(result, indent=2))
output_filename = 'kansen_check_junbi_output.txt'
with open(output_filename, 'w', encoding='utf-8') as f:
json.dump(result, f, indent=2, ensure_ascii=False)
print(f"結果を {output_filename} に出力しました。")
package-lock.json
の解析
2. import json
# Read the compromised packages list from the generated file
try:
with open('kansen_check_junbi_output.txt', 'r', encoding='utf-8') as f:
shai_hulud_packages = json.load(f)
except FileNotFoundError:
print("エラー: kansen_check_junbi_output.txt が見つかりません。")
print("先に kansen_check_junbi.py を実行してください。")
shai_hulud_packages = {}
except json.JSONDecodeError:
print("エラー: kansen_check_junbi_output.txt の内容が正しいJSON形式ではありません。")
shai_hulud_packages = {}
def check_package_lock(file_path, compromised_list):
with open(file_path, "r", encoding="utf-8") as f:
data = json.load(f)
results = []
# npm v7+ の形式
packages = data.get("packages", {})
for pkg_path, pkg_info in packages.items():
if pkg_path.startswith("node_modules/"):
pkg_name = pkg_path.replace("node_modules/", "")
version = pkg_info.get("version")
if pkg_name in compromised_list and version in compromised_list[pkg_name]:
results.append((pkg_name, version))
# npm v6以前の形式
dependencies = data.get("dependencies", {})
def recursive_check(deps):
for name, info in deps.items():
version = info.get("version")
if name in compromised_list and version in compromised_list[name]:
results.append((name, version))
if "dependencies" in info:
recursive_check(info["dependencies"])
recursive_check(dependencies)
return results
if __name__ == "__main__":
lock_path = "../package-lock.json"
compromised = check_package_lock(lock_path, shai_hulud_packages)
if compromised:
print("感染パッケージが見つかりました!")
for pkg, ver in compromised:
print(f"{pkg}@{ver} は感染バージョンです")
else:
print("感染パッケージは見つかりませんでした")
使い方
NPMパッケージ感染チェッカー
このツールは、package-lock.json
ファイルに記載されているNPMパッケージの中に、潜在的に危険な(汚染された)パッケージが含まれていないかチェックするためのPythonスクリプトです。
参考:https://qiita.com/ebisawa_a/items/5e6872b82da116892b2f
ファイル構成
-
kansen_check_junbi.py
: 汚染されたパッケージのリストを準備します。 -
kansen_check_junbi_output.txt
: 生成された汚染パッケージのリスト(Pythonの辞書形式)。 -
kansen_check.py
: あなたのプロジェクトに対してチェックを実行します。
ファイルの配置
├ package-lock.json
├ kansen_check
│ ├ kansen_check_junbi.py
│ ├ kansen_check.py
│ └ kansen_check_junbi_output.txt
│
ステップ1:汚染パッケージリストの更新
-
kansen_check_junbi.py
を編集する:
このスクリプトを開き、input_js
変数を最新の汚染パッケージリストで更新します。形式はJavaScriptのオブジェクト配列です。 -
スクリプトを実行する:
kansen_check
ディレクトリ内で、以下のコマンドを実行します。python kansen_check_junbi.py
これにより、
kansen_check_junbi_output.txt
ファイルが生成または更新されます。(巻末に記載してあります)
ダミーを入れてみる(package-lock.jsonにあるモジュールをダミーで入れて検出できているかチェックする方法)
例:以下のモジュールがpackage-lock.jsonにある場合。
"node_modules/@babel/code-frame": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
"integrity": "sha***Fg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/helper-validator-identifier": "^7.27.1",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
"engines": {
"node": ">=6.9.0"
}
},
以下のように必要な情報だけに変更して、kansen_check\kansen_check_junbi_output.txtに追記
"@babel/code-frame": [
"7.27.1"
],
ステップ2:プロジェクトのチェック
-
チェック用のスクリプトを実行する:
package-lock.json
と同階層のkansen_checkにあるkansen_check.py
スクリプトを実行します。cd kansen_check python kansen_check.py
-
結果を確認する:
- 汚染されたパッケージが見つからない場合、
感染パッケージは見つかりませんでした
と表示されます。 - 汚染されたパッケージが見つかった場合、そのパッケージ名とバージョンの一覧が表示されます。
- 汚染されたパッケージが見つからない場合、
例:
感染パッケージが見つかりました!
@babel/code-frame@7.27.1 は感染バージョンです
注意;動作確認のためダミーで@babel/code-frame@7.27.1 入れた場合なので、これは、安全です。
動作の仕組み
- 汚染されたパッケージのリストは、
kansen_check_junbi.py
内のinput_js
変数で定義されます。このリストのキーは、node_modules/
という接頭辞を含まない、正確なパッケージ名(例:@babel/code-frame
)である必要があります。 -
kansen_check.py
は、生成された.txt
ファイルを読み込み、あなたのプロジェクトの../package-lock.json
に記載されているパッケージ名およびバージョンと比較します。
まとめ
- Shai-Huludはnpmのサプライチェーンを狙った自己伝播型マルウェア
- 私のWindows11ではsafe-chainはインストールできなかった
- Qiitaの感染リストをPython辞書に変換して活用
package-lock.json
を解析した - safe-chainはnpm install前に検出可能だが、
package-lock.json
を解析する方法は、すでにインストールされているものを調べているので感染は防げない。 - 私の場合、感染はしていなかった。ただし、現状報告されているモジュールだけしか調べられていない。
- 今後、safe-chainの更新を待って再挑戦。
おまけ
kansen_check\kansen_check_junbi_output.txtの中身
{
"@ahmedhfarag/ngx-perfect-scrollbar": [
"20.0.20"
],
"@ahmedhfarag/ngx-virtual-scroller": [
"4.0.4"
],
"@art-ws/common": [
"2.0.22"
],
"@art-ws/config-eslint": [
"2.0.4",
"2.0.5"
],
"@art-ws/config-ts": [
"2.0.7",
"2.0.8"
],
"@art-ws/db-context": [
"2.0.21"
],
"@art-ws/di": [
"2.0.28"
],
"@art-ws/di-node": [
"2.0.13"
],
"@art-ws/eslint": [
"1.0.5",
"1.0.6"
],
"@art-ws/fastify-http-server": [
"2.0.24"
],
"@art-ws/http-server": [
"2.0.21"
],
"@art-ws/openapi": [
"0.1.9"
],
"@art-ws/package-base": [
"1.0.5",
"1.0.6"
],
"@art-ws/prettier": [
"1.0.5",
"1.0.6"
],
"@art-ws/slf": [
"2.0.15"
],
"@art-ws/ssl-info": [
"1.0.9",
"1.0.10"
],
"@art-ws/web-app": [
"1.0.3",
"1.0.4"
],
"@crowdstrike/commitlint": [
"8.1.1",
"8.1.2"
],
"@crowdstrike/falcon-shoelace": [
"0.4.1"
],
"@crowdstrike/foundry-js": [
"0.19.1",
"0.19.2"
],
"@crowdstrike/glide-core": [
"0.34.2",
"0.34.3"
],
"@crowdstrike/logscale-dashboard": [
"1.205.1",
"1.205.2"
],
"@crowdstrike/logscale-file-editor": [
"1.205.1",
"1.205.2"
],
"@crowdstrike/logscale-parser-edit": [
"1.205.1",
"1.205.2"
],
"@crowdstrike/logscale-search": [
"1.205.1",
"1.205.2"
],
"@crowdstrike/tailwind-toucan-base": [
"5.0.1",
"5.0.2"
],
"@ctrl/deluge": [
"7.2.1",
"7.2.2"
],
"@ctrl/golang-template": [
"1.4.2",
"1.4.3"
],
"@ctrl/magnet-link": [
"4.0.3",
"4.0.4"
],
"@ctrl/ngx-codemirror": [
"7.0.1",
"7.0.2"
],
"@ctrl/ngx-csv": [
"6.0.1",
"6.0.2"
],
"@ctrl/ngx-emoji-mart": [
"9.2.1",
"9.2.2"
],
"@ctrl/ngx-rightclick": [
"4.0.1",
"4.0.2"
],
"@ctrl/qbittorrent": [
"9.7.1",
"9.7.2"
],
"@ctrl/react-adsense": [
"2.0.1",
"2.0.2"
],
"@ctrl/shared-torrent": [
"6.3.1",
"6.3.2"
],
"@ctrl/tinycolor": [
"4.1.1",
"4.1.2"
],
"@ctrl/torrent-file": [
"4.1.1",
"4.1.2"
],
"@ctrl/transmission": [
"7.3.1"
],
"@ctrl/ts-base32": [
"4.0.1",
"4.0.2"
],
"@hestjs/core": [
"0.2.1"
],
"@hestjs/cqrs": [
"0.1.6"
],
"@hestjs/demo": [
"0.1.2"
],
"@hestjs/eslint-config": [
"0.1.2"
],
"@hestjs/logger": [
"0.1.6"
],
"@hestjs/scalar": [
"0.1.7"
],
"@hestjs/validation": [
"0.1.6"
],
"@nativescript-community/arraybuffers": [
"1.1.6",
"1.1.7",
"1.1.8"
],
"@nativescript-community/gesturehandler": [
"2.0.35"
],
"@nativescript-community/perms": [
"3.0.5",
"3.0.6",
"3.0.7",
"3.0.8"
],
"@nativescript-community/sqlite": [
"3.5.2",
"3.5.3",
"3.5.4",
"3.5.5"
],
"@nativescript-community/text": [
"1.6.9",
"1.6.10",
"1.6.11",
"1.6.12"
],
"@nativescript-community/typeorm": [
"0.2.30",
"0.2.31",
"0.2.32",
"0.2.33"
],
"@nativescript-community/ui-collectionview": [
"6.0.6"
],
"@nativescript-community/ui-document-picker": [
"1.1.27",
"1.1.28"
],
"@nativescript-community/ui-drawer": [
"0.1.30"
],
"@nativescript-community/ui-image": [
"4.5.6"
],
"@nativescript-community/ui-label": [
"1.3.35",
"1.3.36",
"1.3.37"
],
"@nativescript-community/ui-material-bottom-navigation": [
"7.2.72",
"7.2.73",
"7.2.74",
"7.2.75"
],
"@nativescript-community/ui-material-bottomsheet": [
"7.2.72"
],
"@nativescript-community/ui-material-core": [
"7.2.72",
"7.2.73",
"7.2.74",
"7.2.75"
],
"@nativescript-community/ui-material-core-tabs": [
"7.2.72",
"7.2.73",
"7.2.74",
"7.2.75"
],
"@nativescript-community/ui-material-ripple": [
"7.2.72",
"7.2.73",
"7.2.74",
"7.2.75"
],
"@nativescript-community/ui-material-tabs": [
"7.2.72",
"7.2.73",
"7.2.74",
"7.2.75"
],
"@nativescript-community/ui-pager": [
"14.1.36",
"14.1.37",
"14.1.38"
],
"@nativescript-community/ui-pulltorefresh": [
"2.5.4",
"2.5.5",
"2.5.6",
"2.5.7"
],
"@nexe/config-manager": [
"0.1.1"
],
"@nexe/eslint-config": [
"0.1.1"
],
"@nexe/logger": [
"0.1.3"
],
"@nstudio/angular": [
"20.0.4",
"20.0.5",
"20.0.6"
],
"@nstudio/focus": [
"20.0.4",
"20.0.5",
"20.0.6"
],
"@nstudio/nativescript-checkbox": [
"2.0.6",
"2.0.7",
"2.0.8",
"2.0.9"
],
"@nstudio/nativescript-loading-indicator": [
"5.0.1",
"5.0.2",
"5.0.3",
"5.0.4"
],
"@nstudio/ui-collectionview": [
"5.1.11",
"5.1.12",
"5.1.13",
"5.1.14"
],
"@nstudio/web": [
"20.0.4"
],
"@nstudio/web-angular": [
"20.0.4"
],
"@nstudio/xplat": [
"20.0.5",
"20.0.6",
"20.0.7"
],
"@nstudio/xplat-utils": [
"20.0.5",
"20.0.6",
"20.0.7"
],
"@operato/board": [
"9.0.36",
"9.0.37",
"9.0.38",
"9.0.39",
"9.0.40",
"9.0.41",
"9.0.42",
"9.0.43",
"9.0.44",
"9.0.45",
"9.0.46"
],
"@operato/data-grist": [
"9.0.29",
"9.0.35",
"9.0.36",
"9.0.37"
],
"@operato/graphql": [
"9.0.22",
"9.0.35",
"9.0.36",
"9.0.37",
"9.0.38",
"9.0.39",
"9.0.40",
"9.0.41",
"9.0.42",
"9.0.43",
"9.0.44",
"9.0.45",
"9.0.46"
],
"@operato/headroom": [
"9.0.2",
"9.0.35",
"9.0.36",
"9.0.37"
],
"@operato/help": [
"9.0.35",
"9.0.36",
"9.0.37",
"9.0.38",
"9.0.39",
"9.0.40",
"9.0.41",
"9.0.42",
"9.0.43",
"9.0.44",
"9.0.45",
"9.0.46"
],
"@operato/i18n": [
"9.0.35",
"9.0.36",
"9.0.37"
],
"@operato/input": [
"9.0.27",
"9.0.35",
"9.0.36",
"9.0.37",
"9.0.38",
"9.0.39",
"9.0.40",
"9.0.41",
"9.0.42",
"9.0.43",
"9.0.44",
"9.0.45",
"9.0.46"
],
"@operato/layout": [
"9.0.35",
"9.0.36",
"9.0.37"
],
"@operato/popup": [
"9.0.22",
"9.0.35",
"9.0.36",
"9.0.37",
"9.0.38",
"9.0.39",
"9.0.40",
"9.0.41",
"9.0.42",
"9.0.43",
"9.0.44",
"9.0.45",
"9.0.46"
],
"@operato/pull-to-refresh": [
"9.0.36",
"9.0.37",
"9.0.38",
"9.0.39",
"9.0.40",
"9.0.41",
"9.0.42"
],
"@operato/shell": [
"9.0.22",
"9.0.35",
"9.0.36",
"9.0.37",
"9.0.38",
"9.0.39"
],
"@operato/styles": [
"9.0.2",
"9.0.35",
"9.0.36",
"9.0.37"
],
"@operato/utils": [
"9.0.22",
"9.0.35",
"9.0.36",
"9.0.37",
"9.0.38",
"9.0.39",
"9.0.40",
"9.0.41",
"9.0.42",
"9.0.43",
"9.0.44",
"9.0.45",
"9.0.46"
],
"@teselagen/bounce-loader": [
"0.3.16",
"0.3.17"
],
"@teselagen/liquibase-tools": [
"0.4.1"
],
"@teselagen/range-utils": [
"0.3.14",
"0.3.15"
],
"@teselagen/react-list": [
"0.8.19",
"0.8.20"
],
"@teselagen/react-table": [
"6.10.19"
],
"@thangved/callback-window": [
"1.1.4"
],
"@things-factory/attachment-base": [
"9.0.43",
"9.0.44",
"9.0.45",
"9.0.46",
"9.0.47",
"9.0.48",
"9.0.49",
"9.0.50"
],
"@things-factory/auth-base": [
"9.0.43",
"9.0.44",
"9.0.45"
]
}
Discussion