diff --git a/.github/workflows/build-example-desktop-mac.yml b/.github/workflows/build-example-desktop-mac.yml new file mode 100644 index 000000000..cee04555d --- /dev/null +++ b/.github/workflows/build-example-desktop-mac.yml @@ -0,0 +1,41 @@ +name: Build Example Desktop (macOS) + +on: + workflow_call: + +jobs: + build-mac: + runs-on: macos-latest + permissions: + contents: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Install dependencies + run: | + echo "📦 Installing dependencies..." + yarn + yarn bootstrap + + - name: Build macOS App + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + cd packages/connect-examples/electron-example + yarn make:mac + + - name: Upload macOS Artifact + uses: actions/upload-artifact@v4 + with: + name: mac-example-desktop + path: packages/connect-examples/electron-example/out/*.dmg + diff --git a/.github/workflows/build-example-desktop-win.yml b/.github/workflows/build-example-desktop-win.yml new file mode 100644 index 000000000..16d0bc882 --- /dev/null +++ b/.github/workflows/build-example-desktop-win.yml @@ -0,0 +1,44 @@ +name: Build Example Desktop (Windows) + +on: + workflow_call: + +jobs: + build-win: + runs-on: windows-latest + permissions: + contents: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '22' + cache: 'yarn' + + - name: Enable long paths on Windows + run: git config --system core.longpaths true + + - name: Install dependencies + run: | + echo "📦 Installing dependencies..." + yarn + yarn bootstrap + + - name: Build Windows App + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + cd packages/connect-examples/electron-example + yarn make:win + + - name: Upload Windows Artifact + uses: actions/upload-artifact@v4 + with: + name: win-example-desktop + path: packages/connect-examples/electron-example/out/*.exe diff --git a/.github/workflows/build-example-desktop.yml b/.github/workflows/build-example-desktop.yml index 55c894f22..313873d3e 100644 --- a/.github/workflows/build-example-desktop.yml +++ b/.github/workflows/build-example-desktop.yml @@ -1,53 +1,16 @@ -name: build-example-desktop +name: Build Example Desktop (All Platforms) -on: workflow_dispatch +on: + workflow_dispatch: -jobs: - build: - runs-on: macos-latest - env: - PROJECT_PATH: packages/connect-examples/electron-example - steps: - - uses: actions/checkout@v4 - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '22' - registry-url: 'https://registry.npmjs.org' - - - name: Install dependencies - run: | - yarn - yarn bootstrap - - - name: Build Target - run: | - yarn build +permissions: + contents: write - - name: Build Desktop Application - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: yarn build:example:desktop - - - name: Upload Mac x64 Artifacts - uses: actions/upload-artifact@v4 - with: - name: mac-x64-example-desktop - path: | - ${{ env.PROJECT_PATH }}/out/*x64.dmg - ${{ env.PROJECT_PATH }}/out/*mac-x64.zip - - - name: Upload Mac arm64 Artifacts - uses: actions/upload-artifact@v4 - with: - name: mac-arm64-example-desktop - path: | - ${{ env.PROJECT_PATH }}/out/*arm64.dmg - ${{ env.PROJECT_PATH }}/out/*mac-arm64.zip +jobs: + build-mac: + uses: ./.github/workflows/build-example-desktop-mac.yml + secrets: inherit - - name: Upload Windows Artifacts - uses: actions/upload-artifact@v4 - with: - name: win-x64-example-desktop - path: | - ${{ env.PROJECT_PATH }}/out/*.exe + build-win: + uses: ./.github/workflows/build-example-desktop-win.yml + secrets: inherit diff --git a/.github/workflows/package-publish.yml b/.github/workflows/package-publish.yml index 5db281ccd..f32d3a6e6 100644 --- a/.github/workflows/package-publish.yml +++ b/.github/workflows/package-publish.yml @@ -35,6 +35,34 @@ jobs: echo "📦 Detected stable version: $VERSION" fi + get-version: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version-info.outputs.version }} + is_prerelease: ${{ steps.version-info.outputs.is_prerelease }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get version information + id: version-info + run: | + # Get version from core package (assuming independent versioning) + VERSION=$(node -p "require('./packages/core/package.json').version") + echo "📦 Package version: $VERSION" + echo "version=$VERSION" >> $GITHUB_OUTPUT + + # Check if this is a prerelease version (contains -) + if [[ "$VERSION" =~ - ]]; then + echo "is_prerelease=true" >> $GITHUB_OUTPUT + echo "📦 Detected prerelease version: $VERSION" + else + echo "is_prerelease=false" >> $GITHUB_OUTPUT + echo "📦 Detected stable version: $VERSION" + fi + publish-and-release: needs: get-version runs-on: ubuntu-latest @@ -69,7 +97,15 @@ jobs: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} run: | echo "📦 Publishing packages to NPM (v${{ needs.get-version.outputs.version }})..." - yarn publish-packages -y --no-verify-access + IS_PRERELEASE=${{ needs.get-version.outputs.is_prerelease }} + + if [ "$IS_PRERELEASE" = "true" ]; then + echo "📦 Publishing with --dist-tag next for prerelease" + yarn publish-packages -y --no-verify-access --dist-tag next + else + echo "📦 Publishing with --dist-tag latest for stable release" + yarn publish-packages -y --no-verify-access --dist-tag latest + fi echo "✅ Packages published successfully" - name: Publication Summary diff --git a/.husky/pre-commit b/.husky/pre-commit index 92c76aae0..83fb05810 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,6 +2,9 @@ # Run tests yarn test +# Run check versions +yarn check-versions + # Run lint:fix yarn lint:staged diff --git a/package.json b/package.json index 95561fcf6..8f99886e0 100644 --- a/package.json +++ b/package.json @@ -30,13 +30,15 @@ "lint:staged": "lint-staged", "test": "lerna run test", "setup": "yarn && yarn bootstrap && yarn build", - "publish-packages": "lerna publish from-package", + "check-versions": "node scripts/check-versions.js", + "publish-packages": "yarn check-versions && lerna publish from-package", "update-protobuf": "lerna run update:protobuf --scope=@onekeyfe/hd-transport", "update-version": "lerna version --no-git-tag-version --force-publish=@onekeyfe/hd-core,@onekeyfe/hd-ble-sdk,@onekeyfe/hd-common-connect-sdk,@onekeyfe/hd-transport-electron,@onekeyfe/hd-transport-emulator,@onekeyfe/hd-transport-http,@onekeyfe/hd-transport-lowlevel,@onekeyfe/hd-transport-react-native,@onekeyfe/hd-transport-web-device,@onekeyfe/hd-transport,@onekeyfe/hd-web-sdk,@onekeyfe/hd-shared", "example": "cd ./packages/connect-examples/expo-example && yarn start", "example:web": "cd ./packages/connect-examples/expo-example && cross-env CONNECT_SRC=https://localhost:8087 yarn start", "example:desktop": "cd ./packages/connect-examples/electron-example && yarn dev", - "build:example:desktop": "cd ./packages/connect-examples/electron-example && yarn make", + "build:example:desktop:mac": "cd ./packages/connect-examples/electron-example && yarn make:mac", + "build:example:desktop:win": "cd ./packages/connect-examples/electron-example && yarn make:win", "example:v2": "cd ./packages/connect-examples/expo-playground && yarn start", "dev:all": "lerna run dev --parallel --ignore expo-example --ignore hardware-example --ignore onekey-hardware-playground", "dev:web": "cd ./packages/hd-web-sdk && yarn dev", @@ -49,6 +51,7 @@ "dev:transport-lowlevel": "cd ./packages/hd-transport-lowlevel && yarn dev", "dev:transport-emulator": "cd ./packages/hd-transport-emulator && yarn dev", "dev:transport-web-device": "cd ./packages/hd-transport-web-device && yarn dev", + "dev:transport-electron": "cd ./packages/hd-transport-electron && yarn dev", "dev:shared": "cd ./packages/shared && yarn dev", "debug:watcher": "node ./scripts/monitor.js" }, @@ -62,7 +65,9 @@ "parse-url": "8.1.0", "braces": "3.0.3", "tmp": "0.2.4", - "micromatch": "4.0.8" + "micromatch": "4.0.8", + "sha.js": "2.4.12", + "cipher-base": "1.0.5" }, "devDependencies": { "@babel/core": "^7.0.0", @@ -78,6 +83,7 @@ "@types/jest": "^27.5.1", "@types/node": "^18.18.8", "@types/shelljs": "^0.8.11", + "electron-builder": "^24.9.1", "babel-jest": "^28.1.3", "babel-loader": "^8.2.5", "cross-env": "^7.0.3", diff --git a/packages/connect-examples/electron-example/electron-builder.config.js b/packages/connect-examples/electron-example/electron-builder.config.js index 787fed260..7c16b7d02 100644 --- a/packages/connect-examples/electron-example/electron-builder.config.js +++ b/packages/connect-examples/electron-example/electron-builder.config.js @@ -11,6 +11,11 @@ module.exports = { productName: 'HardwareExample', copyright: 'Copyright © OeKey 2024', asar: true, + // Unpack native modules so they can be loaded at runtime + asarUnpack: [ + 'node_modules/@stoprocent/noble/**', + 'node_modules/@stoprocent/bluetooth-hci-socket/**', + ], buildVersion: version, directories: { output: 'out', diff --git a/packages/connect-examples/electron-example/package.json b/packages/connect-examples/electron-example/package.json index cb9f8464e..d5235f334 100644 --- a/packages/connect-examples/electron-example/package.json +++ b/packages/connect-examples/electron-example/package.json @@ -2,7 +2,7 @@ "name": "hardware-example", "productName": "HardwareExample", "executableName": "onekey-hardware-example", - "version": "1.1.10-alpha.1", + "version": "1.1.10", "author": "OneKey", "description": "End-to-end encrypted workspaces for teams", "main": "dist/index.js", @@ -15,12 +15,15 @@ "dev": "npx concurrently \"yarn dev:electron\" \"cross-env TRANSFORM_REGENERATOR_DISABLED=true BROWSER=none yarn dev-electron-web\"", "dev:electron": "electron --inspect=5858 dist/index.js", "build:main": "webpack --config webpack.config.ts", - "make": "yarn clean:build && yarn build-electron-web && electron-builder build -mw --config electron-builder.config.js --publish always", + "rebuild:deps": "electron-builder install-app-deps", + "make:mac": "yarn rebuild:deps && yarn clean:build && yarn build-electron-web && electron-builder build --mac --config electron-builder.config.js --publish always", + "make:win": "yarn rebuild:deps && yarn clean:build && yarn build-electron-web && electron-builder build --win --config electron-builder.config.js --publish always", "lint": "eslint --ext .tsx --ext .ts ./", "ts:check": "yarn tsc --noEmit" }, "dependencies": { - "@abandonware/noble": "^1.9.2-26", + "@onekeyfe/hd-transport-electron": "1.1.10", + "@stoprocent/noble": "2.3.4", "debug": "4.3.4", "electron-is-dev": "^3.0.1", "electron-log": "^5.1.5", diff --git a/packages/connect-examples/electron-example/src/index.ts b/packages/connect-examples/electron-example/src/index.ts index bc8e01997..4d60a4fc4 100644 --- a/packages/connect-examples/electron-example/src/index.ts +++ b/packages/connect-examples/electron-example/src/index.ts @@ -257,8 +257,6 @@ function createMainWindow() { } }); - initNobleBleSupport(browserWindow.webContents); - ipcMain.on(ipcMessageKeys.APP_RESTART, () => { browserWindow?.reload(); }); @@ -283,6 +281,15 @@ if (!singleInstance && !process.mas) { if (!mainWindow) { mainWindow = createMainWindow(); } + + try { + log.info('Initializing Noble BLE support...'); + initNobleBleSupport(mainWindow.webContents); + log.info('Noble BLE support initialized successfully.'); + } catch (e) { + log.error('Failed to initialize Noble BLE support:', e); + } + initChildProcess(); showMainWindow(); console.log('日志文件位置:', log.transports.file.getFile().path); diff --git a/packages/connect-examples/electron-example/webpack.config.ts b/packages/connect-examples/electron-example/webpack.config.ts index 089349b19..5950a16f4 100644 --- a/packages/connect-examples/electron-example/webpack.config.ts +++ b/packages/connect-examples/electron-example/webpack.config.ts @@ -48,8 +48,9 @@ module.exports = { }), }), { - '@abandonware/noble': 'commonjs @abandonware/noble', - '@abandonware/bluetooth-hci-socket': 'commonjs @abandonware/bluetooth-hci-socket', + '@onekeyfe/hd-transport-electron': 'commonjs @onekeyfe/hd-transport-electron', + '@stoprocent/noble': 'commonjs @stoprocent/noble', + '@stoprocent/bluetooth-hci-socket': 'commonjs @stoprocent/bluetooth-hci-socket', bufferutil: 'commonjs bufferutil', 'utf-8-validate': 'commonjs utf-8-validate', }, diff --git a/packages/connect-examples/expo-example/package.json b/packages/connect-examples/expo-example/package.json index c2b299def..658080db3 100644 --- a/packages/connect-examples/expo-example/package.json +++ b/packages/connect-examples/expo-example/package.json @@ -1,13 +1,13 @@ { "name": "expo-example", - "version": "1.1.10-alpha.2", + "version": "1.1.10", "scripts": { "start": "cross-env CONNECT_SRC=https://localhost:8087/ yarn expo start --dev-client", "android": "yarn expo run:android", "ios": "yarn expo run:ios", "web": "yarn expo start --web", "dev:electron-web": "cross-env NODE_OPTIONS=--openssl-legacy-provider cross-env EXPO_ELECTRON_MODE=true yarn web", - "build:electron-web": "cross-env NODE_ENV=production EXPO_ELECTRON_MODE=true yarn expo export:web && node scripts/moveWebBuild.js", + "build:electron-web": "cross-env NODE_OPTIONS=--max-old-space-size=4096 cross-env NODE_ENV=production EXPO_ELECTRON_MODE=true yarn expo export:web && node scripts/moveWebBuild.js", "eject": "yarn expo eject" }, "dependencies": { @@ -19,10 +19,10 @@ "@noble/ed25519": "^2.1.0", "@noble/hashes": "^1.3.3", "@noble/secp256k1": "^1.7.1", - "@onekeyfe/hd-ble-sdk": "1.1.10-alpha.2", - "@onekeyfe/hd-common-connect-sdk": "1.1.10-alpha.2", - "@onekeyfe/hd-core": "1.1.10-alpha.2", - "@onekeyfe/hd-web-sdk": "1.1.10-alpha.2", + "@onekeyfe/hd-ble-sdk": "1.1.10", + "@onekeyfe/hd-common-connect-sdk": "1.1.10", + "@onekeyfe/hd-core": "1.1.10", + "@onekeyfe/hd-web-sdk": "1.1.10", "@onekeyfe/react-native-ble-utils": "^0.1.3", "@polkadot/util-crypto": "13.1.1", "@react-native-async-storage/async-storage": "1.21.0", diff --git a/packages/connect-examples/expo-example/src/components/BaseTestRunner/useRunnerTest.ts b/packages/connect-examples/expo-example/src/components/BaseTestRunner/useRunnerTest.ts index 72d1f0d01..55cce2fcc 100644 --- a/packages/connect-examples/expo-example/src/components/BaseTestRunner/useRunnerTest.ts +++ b/packages/connect-examples/expo-example/src/components/BaseTestRunner/useRunnerTest.ts @@ -424,6 +424,7 @@ export function useRunnerTest(config: RunnerConfig) { initTestCase, store, stateManager, + preCheckResponse, clearItemVerifyState, endTestRunner, setFailedTasks, diff --git a/packages/connect-examples/expo-example/src/components/DeviceList.tsx b/packages/connect-examples/expo-example/src/components/DeviceList.tsx index 82625f4cd..3411730ad 100644 --- a/packages/connect-examples/expo-example/src/components/DeviceList.tsx +++ b/packages/connect-examples/expo-example/src/components/DeviceList.tsx @@ -27,6 +27,8 @@ export type Device = { name: string; features?: Features; deviceType?: string; + id?: string; + state?: string; }; const CONNECTION_TYPE_STORE_KEY = '@onekey/connectionType'; @@ -126,7 +128,13 @@ function DeviceListFC( const response = await sdk.searchDevices(); const foundDevices = (response.payload as unknown as Device[]) ?? []; setDeviceActions({ type: 'setList', payload: foundDevices }); - if (Platform.OS === 'web' && foundDevices?.length) { + + // 🔧 DESKTOP BLE FIX: Don't auto-select devices, let user choose manually + // This prevents automatic connection which can cause issues with device switching + // Users should manually click the "Connect Device" button for their desired device + + // Only auto-select for non-desktop-web-ble connections to maintain backward compatibility + if (Platform.OS === 'web' && foundDevices?.length && connectionType !== 'desktop-web-ble') { const device = foundDevices[0]; selectDevice(device); } diff --git a/packages/connect-examples/expo-example/src/views/FirmwareScreen/index.tsx b/packages/connect-examples/expo-example/src/views/FirmwareScreen/index.tsx index 29315b533..3bc38db45 100644 --- a/packages/connect-examples/expo-example/src/views/FirmwareScreen/index.tsx +++ b/packages/connect-examples/expo-example/src/views/FirmwareScreen/index.tsx @@ -407,44 +407,65 @@ function FirmwareUpdate({ onDisconnectDevice, onReconnectDevice }: FirmwareUpdat } = getDeviceBasicInfo(features, onekeyFeatures); const deviceTypeLowerCase = deviceType.toLowerCase(); - const loadOnekeyFeatures = useCallback(() => { - if (!sdk) return; - sdk.getOnekeyFeatures(selectDevice?.connectId).then(res => { + const loadOnekeyFeatures = useCallback(async () => { + if (!sdk || !selectDevice?.connectId) return undefined; + + try { + console.log('loadOnekeyFeatures: Starting to load OneKey features...'); + const res = await sdk.getOnekeyFeatures(selectDevice.connectId); + console.log('loadOnekeyFeatures: Result:', res); + if (res.success) { - setOnekeyFeatures(res.payload); - } else { - setOnekeyFeatures(undefined); + return res.payload; } - }); + return undefined; + } catch (error) { + console.error('loadOnekeyFeatures: Error:', error); + return undefined; + } }, [sdk, selectDevice?.connectId]); useEffect(() => { if (!sdk) return; - if (selectDevice?.connectId == null || selectDevice?.features == null) { + if (selectDevice?.connectId == null) { setFeatures(undefined); setOnekeyFeatures(undefined); return; } - setConnecting(true); - setFeatures(undefined); - sdk - .getFeatures(selectDevice?.connectId) - .then(res => { - if (res.success) { - setFeatures(res.payload); - loadOnekeyFeatures(); + const loadDeviceFeatures = async () => { + setConnecting(true); + setFeatures(undefined); + setOnekeyFeatures(undefined); + setError(undefined); + + try { + console.log('Loading device features for:', selectDevice.connectId); + + const featuresRes = await sdk.getFeatures(selectDevice.connectId); + console.log('getFeatures result:', featuresRes); + + if (featuresRes.success) { + const fetchedFeatures = featuresRes.payload; + console.log('Features loaded successfully, now loading OneKey features...'); + const fetchedOnekeyFeatures = await loadOnekeyFeatures(); + + setFeatures(fetchedFeatures); + setOnekeyFeatures(fetchedOnekeyFeatures); } else { - setError(res.payload.error); + console.error('Failed to get features:', featuresRes.payload.error); + setError(featuresRes.payload.error); } - }) - .catch(e => { - setError(e.message); - }) - .finally(() => { + } catch (error) { + console.error('Exception in loadDeviceFeatures:', error); + setError(error instanceof Error ? error.message : String(error)); + } finally { setConnecting(false); - }); - }, [loadOnekeyFeatures, sdk, selectDevice?.connectId, selectDevice?.features]); + } + }; + + loadDeviceFeatures(); + }, [sdk, selectDevice?.connectId, loadOnekeyFeatures]); const disconnectDevice = useCallback(() => { setFeatures(undefined); @@ -544,14 +565,21 @@ function FirmwareUpdate({ onDisconnectDevice, onReconnectDevice }: FirmwareUpdat if (type === 'ble' || type === 'firmware') { setShowUpdateDialog(true); - const res = await sdk.firmwareUpdateV2( - Platform.OS === 'web' ? undefined : selectDevice.connectId, - { - binary: fileData, - updateType: type, - platform: 'web', - } - ); + console.log('Starting firmware update:', { + type, + deviceId: selectDevice.connectId, + platform: 'web', + }); + + // For desktop-web-ble mode, we need to pass the connectId + const deviceId = selectDevice.connectId; + console.log('Using device ID for firmware update:', deviceId); + + const res = await sdk.firmwareUpdateV2(deviceId, { + binary: fileData, + updateType: type, + platform: 'web', + }); setShowUpdateDialog(false); if (!res.success) { return { @@ -635,12 +663,21 @@ function FirmwareUpdate({ onDisconnectDevice, onReconnectDevice }: FirmwareUpdat {connecting && ( )} + {!selectDevice && ( )} {!!error && } + {features && !onekeyFeatures && ( + + )} + {selectDevice && selectDevice.state === 'disconnected' && ( + + )} {features && ( diff --git a/packages/connect-examples/expo-example/webpack.config.js b/packages/connect-examples/expo-example/webpack.config.js index f314bce88..2014de19c 100644 --- a/packages/connect-examples/expo-example/webpack.config.js +++ b/packages/connect-examples/expo-example/webpack.config.js @@ -7,9 +7,12 @@ const webpack = require('webpack'); module.exports = async function (env, argv) { const config = await createExpoWebpackConfigAsync(env, argv); - // 设置 publicPath 为 GitHub Pages 的路径 + // 设置 publicPath: + // - Electron 打包(EXPO_ELECTRON_MODE=true)使用根路径,避免 file:// 协议下以 /expo-example/ 为前缀导致 404 + // - 普通生产环境(例如 GitHub Pages)使用 /expo-example/ + const isElectronMode = process.env.EXPO_ELECTRON_MODE === 'true'; if (process.env.NODE_ENV === 'production') { - config.output.publicPath = '/expo-example/'; + config.output.publicPath = isElectronMode ? '/' : '/expo-example/'; } else { // 开发环境使用根路径 config.output.publicPath = '/'; diff --git a/packages/connect-examples/expo-playground/package.json b/packages/connect-examples/expo-playground/package.json index 0fa956e08..2c72e9cf8 100644 --- a/packages/connect-examples/expo-playground/package.json +++ b/packages/connect-examples/expo-playground/package.json @@ -1,6 +1,6 @@ { "name": "onekey-hardware-playground", - "version": "1.1.10-alpha.2", + "version": "1.1.10", "private": true, "sideEffects": [ "app/utils/shim.js", @@ -17,9 +17,9 @@ }, "dependencies": { "@noble/hashes": "^1.8.0", - "@onekeyfe/hd-core": "1.1.10-alpha.2", - "@onekeyfe/hd-shared": "1.1.10-alpha.2", - "@onekeyfe/hd-web-sdk": "1.1.10-alpha.2", + "@onekeyfe/hd-core": "1.1.10", + "@onekeyfe/hd-shared": "1.1.10", + "@onekeyfe/hd-web-sdk": "1.1.10", "@radix-ui/react-checkbox": "^1.3.2", "@radix-ui/react-dialog": "^1.1.14", "@radix-ui/react-dropdown-menu": "^2.1.15", diff --git a/packages/core/package.json b/packages/core/package.json index d6a1a120b..94fbfa597 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,7 +1,7 @@ { "name": "@onekeyfe/hd-core", - "version": "1.1.10-alpha.2", - "description": "> TODO: description", + "version": "1.1.10", + "description": "Core processes and APIs for communicating with OneKey hardware devices.", "author": "OneKey", "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme", "license": "ISC", @@ -25,8 +25,8 @@ "url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues" }, "dependencies": { - "@onekeyfe/hd-shared": "1.1.10-alpha.2", - "@onekeyfe/hd-transport": "1.1.10-alpha.2", + "@onekeyfe/hd-shared": "1.1.10", + "@onekeyfe/hd-transport": "1.1.10", "axios": "^0.27.2", "bignumber.js": "^9.0.2", "bytebuffer": "^5.0.1", diff --git a/packages/hd-ble-sdk/package.json b/packages/hd-ble-sdk/package.json index 2e2ba1a6d..92277b378 100644 --- a/packages/hd-ble-sdk/package.json +++ b/packages/hd-ble-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/hd-ble-sdk", - "version": "1.1.10-alpha.2", + "version": "1.1.10", "author": "OneKey", "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme", "license": "ISC", @@ -20,8 +20,8 @@ "lint:fix": "eslint . --fix" }, "dependencies": { - "@onekeyfe/hd-core": "1.1.10-alpha.2", - "@onekeyfe/hd-shared": "1.1.10-alpha.2", - "@onekeyfe/hd-transport-react-native": "1.1.10-alpha.2" + "@onekeyfe/hd-core": "1.1.10", + "@onekeyfe/hd-shared": "1.1.10", + "@onekeyfe/hd-transport-react-native": "1.1.10" } } diff --git a/packages/hd-common-connect-sdk/package.json b/packages/hd-common-connect-sdk/package.json index c9ac5727e..9a6949534 100644 --- a/packages/hd-common-connect-sdk/package.json +++ b/packages/hd-common-connect-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/hd-common-connect-sdk", - "version": "1.1.10-alpha.2", + "version": "1.1.10", "author": "OneKey", "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme", "license": "ISC", @@ -20,11 +20,11 @@ "lint:fix": "eslint . --fix" }, "dependencies": { - "@onekeyfe/hd-core": "1.1.10-alpha.2", - "@onekeyfe/hd-shared": "1.1.10-alpha.2", - "@onekeyfe/hd-transport-emulator": "1.1.10-alpha.2", - "@onekeyfe/hd-transport-http": "1.1.10-alpha.2", - "@onekeyfe/hd-transport-lowlevel": "1.1.10-alpha.2", - "@onekeyfe/hd-transport-web-device": "1.1.10-alpha.2" + "@onekeyfe/hd-core": "1.1.10", + "@onekeyfe/hd-shared": "1.1.10", + "@onekeyfe/hd-transport-emulator": "1.1.10", + "@onekeyfe/hd-transport-http": "1.1.10", + "@onekeyfe/hd-transport-lowlevel": "1.1.10", + "@onekeyfe/hd-transport-web-device": "1.1.10" } } diff --git a/packages/hd-transport-electron/package.json b/packages/hd-transport-electron/package.json index 02d864ade..ade4b5624 100644 --- a/packages/hd-transport-electron/package.json +++ b/packages/hd-transport-electron/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/hd-transport-electron", - "version": "1.1.10-alpha.2", + "version": "1.1.10", "author": "OneKey", "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme", "license": "MIT", @@ -25,7 +25,11 @@ "electron-log": ">=4.0.0" }, "dependencies": { - "@onekeyfe/hd-shared": "1.1.10-alpha.2" + "@onekeyfe/hd-core": "1.1.10", + "@onekeyfe/hd-shared": "1.1.10", + "@onekeyfe/hd-transport": "1.1.10", + "@stoprocent/noble": "2.3.4", + "p-retry": "^4.6.2" }, "devDependencies": { "@types/web-bluetooth": "^0.0.17", diff --git a/packages/hd-transport-electron/src/ble-ops.ts b/packages/hd-transport-electron/src/ble-ops.ts new file mode 100644 index 000000000..3205d38f4 --- /dev/null +++ b/packages/hd-transport-electron/src/ble-ops.ts @@ -0,0 +1,77 @@ +import type { Characteristic } from '@stoprocent/noble'; +import type { Logger } from './types/noble-extended'; + +export interface SoftRefreshParams { + deviceId: string; + notifyCharacteristic: Characteristic | null | undefined; + subscriptionOperations: Map; + subscribedDevices: Map; + pairedDevices: Set; + notificationCallbacks: Map void>; + processNotificationData: ( + deviceId: string, + data: Buffer + ) => { + isComplete: boolean; + completePacket?: string; + error?: string; + }; + logger: Logger | null; +} + +export async function softRefreshSubscription(params: SoftRefreshParams): Promise { + const { + deviceId, + notifyCharacteristic, + subscriptionOperations, + subscribedDevices, + pairedDevices, + notificationCallbacks, + processNotificationData, + logger, + } = params; + + if (!notifyCharacteristic) { + throw new Error(`Notify characteristic not available for device ${deviceId}`); + } + + logger?.info('[BLE-OPS] Starting subscription refresh', { deviceId }); + + subscriptionOperations.set(deviceId, 'subscribing'); + + await new Promise(resolve => { + notifyCharacteristic.unsubscribe(() => resolve()); + }); + + await new Promise((resolve, reject) => { + notifyCharacteristic.subscribe((error?: Error) => { + if (error) { + reject(error); + return; + } + resolve(); + }); + }); + + notifyCharacteristic.removeAllListeners('data'); + notifyCharacteristic.on('data', (data: Buffer) => { + if (!pairedDevices.has(deviceId)) { + pairedDevices.add(deviceId); + logger?.info('[BLE-OPS] Device paired successfully', { deviceId }); + } + + const result = processNotificationData(deviceId, data); + if (result.error) { + logger?.error('[BLE-OPS] Packet processing error:', result.error); + return; + } + if (result.isComplete && result.completePacket) { + const appCb = notificationCallbacks.get(deviceId); + if (appCb) appCb(result.completePacket); + } + }); + + subscribedDevices.set(deviceId, true); + subscriptionOperations.set(deviceId, 'idle'); + logger?.info('[BLE-OPS] Subscription refresh completed', { deviceId }); +} diff --git a/packages/hd-transport-electron/src/noble-ble-handler.ts b/packages/hd-transport-electron/src/noble-ble-handler.ts index 8bcd12c29..50b277a63 100644 --- a/packages/hd-transport-electron/src/noble-ble-handler.ts +++ b/packages/hd-transport-electron/src/noble-ble-handler.ts @@ -18,10 +18,11 @@ import { } from '@onekeyfe/hd-shared'; import { COMMON_HEADER_SIZE } from '@onekeyfe/hd-transport'; import type { WebContents, IpcMainInvokeEvent } from 'electron'; -import type { Peripheral, Service, Characteristic } from '@abandonware/noble'; +import type { Peripheral, Service, Characteristic } from '@stoprocent/noble'; import pRetry from 'p-retry'; import type { NobleModule, Logger, DeviceInfo, CharacteristicPair } from './types/noble-extended'; import { safeLog } from './types/noble-extended'; +import { softRefreshSubscription } from './ble-ops'; // Noble will be dynamically imported to avoid bundlinpissues let noble: NobleModule | null = null; @@ -44,6 +45,7 @@ let persistentStateListener: ((state: string) => void) | null = null; // Device cache and connection state const discoveredDevices = new Map(); const connectedDevices = new Map(); +const pairedDevices = new Set(); // Windows BLE 设备配对状态跟踪 const deviceCharacteristics = new Map(); const notificationCallbacks = new Map void>(); const subscribedDevices = new Map(); // Track subscription status @@ -60,9 +62,11 @@ interface PacketAssemblyState { } const devicePacketStates = new Map(); -// Track recent write operations to detect pairing rejection -const recentWriteOperations = new Map(); // deviceId -> timestamp -const WRITE_DISCONNECT_THRESHOLD = 1000; // 1 second +// Windows-only response watchdog state moved to utils/windows-ble-recovery + +// Pairing-related state removed + +// Device operation history removed // Service UUIDs to scan for - using constants from hd-shared const ONEKEY_SERVICE_UUIDS = [ONEKEY_SERVICE_UUID]; @@ -76,11 +80,16 @@ const BLUETOOTH_INIT_TIMEOUT = 10000; // 10 seconds for Bluetooth initialization const DEVICE_SCAN_TIMEOUT = 5000; // 5 seconds for device scanning const FAST_SCAN_TIMEOUT = 1500; // 1.5 seconds for fast targeted scanning const DEVICE_CHECK_INTERVAL = 500; // 500ms interval for periodic device checks -const CONNECTION_TIMEOUT = 3000; // 15 seconds for device connection -const CHUNK_WRITE_DELAY = 10; // 10ms delay between chunk writes +const CONNECTION_TIMEOUT = 3000; // 3 seconds for device connection -// BLE packet size constants -const BLE_PACKET_SIZE = 192; // Use Android packet size as default for desktop +// Write-related constants +const BLE_PACKET_SIZE = 192; +const UNIFIED_WRITE_DELAY = 5; +const RETRY_CONFIG = { MAX_ATTEMPTS: 15, WRITE_TIMEOUT: 2000 } as const; +const IS_WINDOWS = process.platform === 'win32'; +const ABORTABLE_WRITE_ERROR_PATTERNS = [ + /status:\s*3/i, // Windows pairing cancelled / GATT write failed +]; // Validation limits const MIN_HEADER_LENGTH = 9; // Minimum header chunk length @@ -94,11 +103,18 @@ interface PacketProcessResult { // Process incoming BLE notification data with proper packet reassembly function processNotificationData(deviceId: string, data: Buffer): PacketProcessResult { + // notification telemetry + logger?.info('[NobleBLE] Notification', { + deviceId, + dataLength: data.length, + }); + // Get or initialize packet state for this device let packetState = devicePacketStates.get(deviceId); if (!packetState) { packetState = { bufferLength: 0, buffer: [], packetCount: 0 }; devicePacketStates.set(deviceId, packetState); + logger?.info('[NobleBLE] Initialized new packet state for device:', deviceId); } try { @@ -109,7 +125,7 @@ function processNotificationData(deviceId: string, data: Buffer): PacketProcessR } // Generate message ID for this packet sequence - const messageId = `${deviceId}-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; + const messageId = `${deviceId}-${Date.now()}-${Math.random().toString(36).substring(2, 11)}`; // Reset packet state for new message packetState.bufferLength = data.readInt32BE(5); @@ -144,6 +160,13 @@ function processNotificationData(deviceId: string, data: Buffer): PacketProcessR const completeBuffer = Buffer.from(packetState.buffer); const hexString = completeBuffer.toString('hex'); + logger?.info('[NobleBLE] Packet assembled', { + deviceId, + totalPackets: packetState.packetCount, + expectedLength: packetState.bufferLength, + actualLength: packetState.buffer.length - COMMON_HEADER_SIZE, + }); + // Reset packet state for next message resetPacketState(packetState); @@ -196,6 +219,52 @@ function setupPersistentStateListener(): void { // Update global state updateBluetoothState(state); + + // When Bluetooth is powered off, clear all device caches and reset state to avoid stale peripherals + if (state === 'poweredOff') { + logger?.info('[NobleBLE] Bluetooth powered off - clearing device caches and resetting state'); + + // Cleanup all connected devices (send disconnect event to renderer) + const connectedIds = Array.from(connectedDevices.keys()); + for (const deviceId of connectedIds) { + try { + cleanupDevice(deviceId, undefined, { + cleanupConnection: true, + sendDisconnectEvent: true, + cancelOperations: true, + reason: 'bluetooth-poweredOff', + }); + } catch (e) { + safeLog(logger, 'error', 'Failed to cleanup device during poweredOff', { + deviceId, + error: e instanceof Error ? e.message : String(e), + }); + } + } + + // Clear discovery and subscription-related states to ensure next connect starts from state-1 + discoveredDevices.clear(); + deviceCharacteristics.clear(); + subscribedDevices.clear(); + notificationCallbacks.clear(); + devicePacketStates.clear(); + subscriptionOperations.clear(); + pairedDevices.clear(); + + // Best-effort stop scanning + if (noble) { + try { + noble.stopScanning(); + } catch (e) { + safeLog( + logger, + 'error', + 'Failed to stop scanning on poweredOff', + e instanceof Error ? e.message : String(e) + ); + } + } + } }; noble.on('stateChange', persistentStateListener); @@ -236,7 +305,7 @@ async function initializeNoble(): Promise { try { // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require - noble = require('@abandonware/noble') as NobleModule; + noble = require('@stoprocent/noble') as NobleModule; logger?.info('[NobleBLE] Noble library loaded'); // Wait for Bluetooth to be ready @@ -302,50 +371,89 @@ async function initializeNoble(): Promise { } } -// Clean up device state - unified function for all cleanup scenarios -function cleanupDeviceState(deviceId: string): void { - connectedDevices.delete(deviceId); - deviceCharacteristics.delete(deviceId); - notificationCallbacks.delete(deviceId); - devicePacketStates.delete(deviceId); - subscribedDevices.delete(deviceId); - recentWriteOperations.delete(deviceId); - // 🔒 Clear operation state - subscriptionOperations.delete(deviceId); - logger?.info('[NobleBLE] Device state cleaned up:', deviceId); +// (Removed) cancelPairing: pairing is handled automatically during Windows init now + +// ===== 统一的设备清理系统 ===== + +/** + * 设备清理选项 + */ +interface DeviceCleanupOptions { + /** 是否清理 BLE 连接状态 */ + cleanupConnection?: boolean; + /** 是否发送断开事件 */ + sendDisconnectEvent?: boolean; + /** 是否取消正在进行的操作 */ + cancelOperations?: boolean; + /** 清理原因(用于日志) */ + reason?: string; } -// Handle device disconnection - unified handler for all disconnect scenarios -function handleDeviceDisconnect(deviceId: string, webContents: WebContents): void { - logger?.error('[NobleBLE] ⚠️ DEVICE DISCONNECT DETECTED:', { +/** + * 统一的设备清理函数 - 所有清理操作的唯一入口 + */ +function cleanupDevice( + deviceId: string, + webContents?: WebContents, + options: DeviceCleanupOptions = {} +): void { + const { + cleanupConnection = true, + sendDisconnectEvent = false, + cancelOperations = true, + reason = 'unknown', + } = options; + + logger?.info('[NobleBLE] Starting device cleanup', { deviceId, - hasPeripheral: connectedDevices.has(deviceId), - hasCharacteristics: deviceCharacteristics.has(deviceId), - stackTrace: new Error().stack?.split('\n').slice(1, 5), + reason, + cleanupConnection, + sendDisconnectEvent, + cancelOperations, }); - // Get device info before cleanup + // 获取设备信息(在清理前) const peripheral = connectedDevices.get(deviceId); const deviceName = peripheral?.advertisement?.localName || 'Unknown Device'; - // Check if this is a pairing rejection (write completed but device disconnected quickly) - const recentWriteTime = recentWriteOperations.get(deviceId); - const now = Date.now(); - const isPairingRejection = recentWriteTime && now - recentWriteTime < WRITE_DISCONNECT_THRESHOLD; + // 1. 清理设备状态 + if (cleanupConnection) { + connectedDevices.delete(deviceId); + deviceCharacteristics.delete(deviceId); + notificationCallbacks.delete(deviceId); + devicePacketStates.delete(deviceId); + subscribedDevices.delete(deviceId); + subscriptionOperations.delete(deviceId); + pairedDevices.delete(deviceId); // 清理windows配对状态 + } - if (isPairingRejection) { - logger?.info('[NobleBLE] Pairing rejection detected, sending error notification'); - // Send pairing rejection error directly to transport - webContents.send(EOneKeyBleMessageKeys.NOBLE_BLE_NOTIFICATION, deviceId, 'PAIRING_REJECTED'); + // 2. 发送断开事件(如果需要) + if (sendDisconnectEvent && webContents) { + webContents.send(EOneKeyBleMessageKeys.BLE_DEVICE_DISCONNECTED, { + id: deviceId, + name: deviceName, + }); } - // Clean up device state - cleanupDeviceState(deviceId); + logger?.info('[NobleBLE] Device cleanup completed', { deviceId, reason }); +} - // Send disconnect event to renderer process - webContents.send(EOneKeyBleMessageKeys.BLE_DEVICE_DISCONNECTED, { - id: deviceId, - name: deviceName, +/** + * 处理设备断开 - 自动断开的情况 + */ +function handleDeviceDisconnect(deviceId: string, webContents: WebContents): void { + logger?.error('[NobleBLE] ⚠️ DEVICE DISCONNECT DETECTED:', { + deviceId, + hasPeripheral: connectedDevices.has(deviceId), + hasCharacteristics: deviceCharacteristics.has(deviceId), + stackTrace: new Error().stack?.split('\n').slice(1, 5), + }); + + cleanupDevice(deviceId, webContents, { + cleanupConnection: true, + sendDisconnectEvent: true, + cancelOperations: true, + reason: 'auto-disconnect', }); } @@ -364,6 +472,205 @@ function setupDisconnectListener( }); } +// ===== Write helpers (inline) ===== + +async function writeCharacteristicWithAck( + deviceId: string, + writeCharacteristic: Characteristic, + buffer: Buffer +): Promise { + return new Promise((resolve, reject) => { + writeCharacteristic.write(buffer, true, (error?: Error) => { + if (error) { + logger?.error('[NobleBLE] Write failed', { deviceId, error: String(error) }); + reject(error); + return; + } + resolve(); + }); + }); +} + +async function attemptWindowsWriteUntilPaired( + deviceId: string, + doGetWriteCharacteristic: () => Characteristic | null | undefined, + payload: Buffer, + contextLabel: string +): Promise { + const timeoutMs = RETRY_CONFIG.WRITE_TIMEOUT; + for (let attempt = 1; attempt <= RETRY_CONFIG.MAX_ATTEMPTS; attempt++) { + // If disconnected, abort + if (!connectedDevices.has(deviceId)) { + throw ERRORS.TypedError( + HardwareErrorCode.BleConnectedError, + `Device ${deviceId} disconnected during retry` + ); + } + + logger?.debug('[BLE-Write] Windows write attempt', { + deviceId, + attempt, + context: contextLabel, + }); + + const latestWrite = doGetWriteCharacteristic(); + if (!latestWrite) { + throw ERRORS.TypedError( + HardwareErrorCode.RuntimeError, + `Write characteristic not available for ${deviceId}` + ); + } + + try { + await writeCharacteristicWithAck(deviceId, latestWrite, payload); + } catch (e) { + const errorMessage = e instanceof Error ? e.message : String(e); + logger?.error('[BLE-Write] Windows write error', { + deviceId, + attempt, + context: contextLabel, + error: errorMessage, + }); + // Abort immediately on known error patterns (e.g., status: 3) + if (ABORTABLE_WRITE_ERROR_PATTERNS.some(p => p.test(errorMessage))) { + await unsubscribeNotifications(deviceId).catch(() => {}); + await disconnectDevice(deviceId).catch(() => {}); + discoveredDevices.delete(deviceId); + subscriptionOperations.set(deviceId, 'idle'); + logger?.info('[NobleBLE] Deep cleanup to reset device state to initial', { deviceId }); + // 置空/重置订阅操作状态,避免后续进入 subscribing 等中间态 + throw ERRORS.TypedError( + HardwareErrorCode.BleConnectedError, + `Write failed with abortable error for device ${deviceId}: ${errorMessage}` + ); + } + } + + // Check if paired already + if (pairedDevices.has(deviceId)) { + logger?.info('[BLE-Write] Windows write success (paired, exiting loop)', { + deviceId, + attempt, + context: contextLabel, + }); + return; + } + + if (attempt < RETRY_CONFIG.MAX_ATTEMPTS) { + await wait(timeoutMs); + } + + if (pairedDevices.has(deviceId)) { + logger?.info('[BLE-Write] Notification observed during wait (paired), exiting loop', { + deviceId, + attempt, + context: contextLabel, + }); + return; + } + + // Try soft refresh first + try { + const notifyCharacteristic = deviceCharacteristics.get(deviceId)?.notify; + await softRefreshSubscription({ + deviceId, + notifyCharacteristic, + subscriptionOperations, + subscribedDevices, + pairedDevices, + notificationCallbacks, + processNotificationData, + logger, + }); + logger?.info('[BLE-Write] Subscription refresh completed', { deviceId }); + } catch (refreshError) { + const errMsg = refreshError instanceof Error ? refreshError.message : String(refreshError); + logger?.error('[BLE-Write] Subscription refresh failed', { deviceId, error: errMsg }); + } + } + + throw ERRORS.TypedError( + HardwareErrorCode.DeviceNotFound, + `No response observed after ${RETRY_CONFIG.MAX_ATTEMPTS} writes: ${deviceId}` + ); +} + +async function transmitHexDataToDevice(deviceId: string, hexData: string): Promise { + const characteristics = deviceCharacteristics.get(deviceId); + const peripheral = connectedDevices.get(deviceId); + if (!peripheral || !characteristics) { + throw ERRORS.TypedError( + HardwareErrorCode.BleCharacteristicNotFound, + `Device ${deviceId} not connected or characteristics not available` + ); + } + + const toBuffer = Buffer.from(hexData, 'hex'); + logger?.info('[NobleBLE] Writing data:', { + deviceId, + dataLength: toBuffer.length, + firstBytes: toBuffer.subarray(0, 8).toString('hex'), + }); + + const doGetWriteCharacteristic = () => deviceCharacteristics.get(deviceId)?.write; + + if (!IS_WINDOWS || pairedDevices.has(deviceId)) { + // macOS / Linux or already paired on Windows: direct write + const writeCharacteristic = doGetWriteCharacteristic(); + if (!writeCharacteristic) { + throw ERRORS.TypedError( + HardwareErrorCode.BleCharacteristicNotFound, + `Write characteristic not available for ${deviceId}` + ); + } + if (toBuffer.length <= BLE_PACKET_SIZE) { + await wait(UNIFIED_WRITE_DELAY); + await writeCharacteristicWithAck(deviceId, writeCharacteristic, toBuffer); + return; + } + // chunked + for (let offset = 0, idx = 0; offset < toBuffer.length; idx++) { + const chunkSize = Math.min(BLE_PACKET_SIZE, toBuffer.length - offset); + const chunk = toBuffer.subarray(offset, offset + chunkSize); + offset += chunkSize; + const latest = doGetWriteCharacteristic(); + if (!latest) { + throw ERRORS.TypedError( + HardwareErrorCode.BleCharacteristicNotFound, + `Write characteristic not available for ${deviceId}` + ); + } + await writeCharacteristicWithAck(deviceId, latest, chunk); + if (offset < toBuffer.length) { + await wait(UNIFIED_WRITE_DELAY); + } + } + return; + } + + // Windows unpaired path: use loop + if (toBuffer.length <= BLE_PACKET_SIZE) { + await wait(UNIFIED_WRITE_DELAY); + await attemptWindowsWriteUntilPaired(deviceId, doGetWriteCharacteristic, toBuffer, 'single'); + return; + } + // chunked loop + for (let offset = 0, idx = 0; offset < toBuffer.length; idx++) { + const chunkSize = Math.min(BLE_PACKET_SIZE, toBuffer.length - offset); + const chunk = toBuffer.subarray(offset, offset + chunkSize); + offset += chunkSize; + await attemptWindowsWriteUntilPaired( + deviceId, + doGetWriteCharacteristic, + chunk, + `chunk-${idx + 1}` + ); + if (offset < toBuffer.length) { + await wait(UNIFIED_WRITE_DELAY); + } + } +} + // Handle discovered device function handleDeviceDiscovered(peripheral: Peripheral): void { const deviceName = peripheral.advertisement?.localName || 'Unknown Device'; @@ -379,13 +686,34 @@ function handleDeviceDiscovered(peripheral: Peripheral): void { discoveredDevices.set(peripheral.id, peripheral); } +// Ensure discover listener is properly set up +// This fixes the issue where devices are not found after web-usb communication failures +function ensureDiscoverListener(): void { + if (!noble) return; + + // Check if discover listener exists by checking listener count + const listenerCount = (noble as any).listenerCount('discover'); + + if (listenerCount === 0) { + logger?.info('[NobleBLE] Discover listener missing, re-adding it'); + noble.on('discover', (peripheral: Peripheral) => { + handleDeviceDiscovered(peripheral); + }); + } else { + logger?.debug('[NobleBLE] Discover listener already exists, count:', listenerCount); + } +} + // Perform targeted scan for a specific device ID async function performTargetedScan(targetDeviceId: string): Promise { if (!noble) { throw ERRORS.TypedError(HardwareErrorCode.RuntimeError, 'Noble not available'); } - // First check if we have a recent cached peripheral\n const cachedDevice = deviceCache.get(targetDeviceId);\n if (cachedDevice && (Date.now() - cachedDevice.lastSeen) < 30000) { // 30 seconds cache\n logger?.info('[NobleBLE] Using cached device for fast connection:', targetDeviceId);\n \n // Use cached device if it was successful before\n if (cachedDevice.connectionSuccess) {\n discoveredDevices.set(targetDeviceId, cachedDevice.peripheral);\n return cachedDevice.peripheral;\n }\n }\n\n logger?.info('[NobleBLE] Starting targeted scan for device:', targetDeviceId); + logger?.info('[NobleBLE] Starting targeted scan for device:', targetDeviceId); + + // Ensure discover listener is properly set up before targeted scanning + ensureDiscoverListener(); return new Promise((resolve, reject) => { const timeout = setTimeout(() => { @@ -402,27 +730,24 @@ async function performTargetedScan(targetDeviceId: string): Promise { // Clear previous discoveries discoveredDevices.clear(); + // Ensure discover listener is properly set up before scanning + // This is crucial to fix the issue where devices are not found after web-usb failures + ensureDiscoverListener(); + return new Promise((resolve, reject) => { const devices: DeviceInfo[] = []; @@ -531,6 +860,21 @@ async function stopScanning(): Promise { }); } +// 清理所有 Noble 监听器(用于应用退出时) +function cleanupNobleListeners(): void { + if (!noble) return; + + // 移除所有监听器以防止内存泄漏 + // Noble 使用 EventEmitter,需要使用 removeAllListeners + try { + (noble as any).removeAllListeners('discover'); + (noble as any).removeAllListeners('stateChange'); + logger?.info('[NobleBLE] All Noble listeners cleaned up'); + } catch (error) { + logger?.error('[NobleBLE] Failed to clean up some listeners:', error); + } +} + // Get device info - supports both discovered and direct connection modes function getDevice(deviceId: string): DeviceInfo | null { // First check if device was discovered through scanning @@ -569,77 +913,82 @@ async function discoverServicesAndCharacteristics( peripheral: Peripheral ): Promise { return new Promise((resolve, reject) => { - peripheral.discoverServices(ONEKEY_SERVICE_UUIDS, (error: string, services: Service[]) => { - if (error) { - logger?.error('[NobleBLE] Service discovery failed:', error); - reject(ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound, error)); - return; - } + peripheral.discoverServices( + ONEKEY_SERVICE_UUIDS, + (error: Error | undefined, services: Service[]) => { + if (error) { + logger?.error('[NobleBLE] Service discovery failed:', error); + reject(ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound, error.message)); + return; + } - if (!services || services.length === 0) { - reject(ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound, 'No OneKey services found')); - return; - } + if (!services || services.length === 0) { + reject( + ERRORS.TypedError(HardwareErrorCode.BleServiceNotFound, 'No OneKey services found') + ); + return; + } - const service = services[0]; // Use first found service - logger?.info('[NobleBLE] Found service:', service.uuid); - - // Discover characteristics - service.discoverCharacteristics( - [ONEKEY_WRITE_CHARACTERISTIC_UUID, ONEKEY_NOTIFY_CHARACTERISTIC_UUID], - (error: string, characteristics: Characteristic[]) => { - if (error) { - logger?.error('[NobleBLE] Characteristic discovery failed:', error); - reject(ERRORS.TypedError(HardwareErrorCode.BleCharacteristicNotFound, error)); - return; - } + const service = services[0]; // Use first found service + logger?.info('[NobleBLE] Found service:', service.uuid); + + // Discover characteristics + service.discoverCharacteristics( + [ONEKEY_WRITE_CHARACTERISTIC_UUID, ONEKEY_NOTIFY_CHARACTERISTIC_UUID], + (error: Error | undefined, characteristics: Characteristic[]) => { + if (error) { + logger?.error('[NobleBLE] Characteristic discovery failed:', error); + reject(ERRORS.TypedError(HardwareErrorCode.BleCharacteristicNotFound, error.message)); + return; + } - // Log discovered characteristics summary - logger?.info('[NobleBLE] Discovered characteristics:', { - count: characteristics?.length || 0, - uuids: characteristics?.map(c => c.uuid) || [], - }); + // Log discovered characteristics summary + logger?.info('[NobleBLE] Discovered characteristics:', { + count: characteristics?.length || 0, + uuids: characteristics?.map(c => c.uuid) || [], + }); - let writeCharacteristic: Characteristic | null = null; - let notifyCharacteristic: Characteristic | null = null; + let writeCharacteristic: Characteristic | null = null; + let notifyCharacteristic: Characteristic | null = null; - // Find characteristics by extracting the distinguishing part of UUID - for (const characteristic of characteristics) { - const uuid = characteristic.uuid.replace(/-/g, '').toLowerCase(); - const uuidKey = uuid.length >= 8 ? uuid.substring(4, 8) : uuid; + // Find characteristics by extracting the distinguishing part of UUID + for (const characteristic of characteristics) { + const uuid = characteristic.uuid.replace(/-/g, '').toLowerCase(); + const uuidKey = uuid.length >= 8 ? uuid.substring(4, 8) : uuid; - if (uuidKey === NORMALIZED_WRITE_UUID) { - writeCharacteristic = characteristic; - } else if (uuidKey === NORMALIZED_NOTIFY_UUID) { - notifyCharacteristic = characteristic; + if (uuidKey === NORMALIZED_WRITE_UUID) { + writeCharacteristic = characteristic; + } else if (uuidKey === NORMALIZED_NOTIFY_UUID) { + notifyCharacteristic = characteristic; + } } - } - logger?.info('[NobleBLE] Characteristic discovery result:', { - writeFound: !!writeCharacteristic, - notifyFound: !!notifyCharacteristic, - }); + logger?.info('[NobleBLE] Characteristic discovery result:', { + writeFound: !!writeCharacteristic, + notifyFound: !!notifyCharacteristic, + }); - if (!writeCharacteristic || !notifyCharacteristic) { - logger?.error( - '[NobleBLE] Missing characteristics - write:', - !!writeCharacteristic, - 'notify:', - !!notifyCharacteristic - ); - reject( - ERRORS.TypedError( - HardwareErrorCode.BleCharacteristicNotFound, - 'Required characteristics not found' - ) - ); - return; - } + if (!writeCharacteristic || !notifyCharacteristic) { + logger?.error( + '[NobleBLE] Missing characteristics - write:', + !!writeCharacteristic, + 'notify:', + !!notifyCharacteristic + ); + reject( + ERRORS.TypedError( + HardwareErrorCode.BleCharacteristicNotFound, + 'Required characteristics not found' + ) + ); + return; + } - resolve({ write: writeCharacteristic, notify: notifyCharacteristic }); - } - ); - }); + resolve({ write: writeCharacteristic, notify: notifyCharacteristic }); + } + ); + } + ); }); } @@ -647,7 +996,15 @@ async function discoverServicesAndCharacteristics( async function forceReconnectPeripheral(peripheral: Peripheral, deviceId: string): Promise { logger?.info('[NobleBLE] Forcing connection reset for device:', deviceId); - // Step 1: Force disconnect if connected + // Step 1: Clean up all device state first + cleanupDevice(deviceId, undefined, { + cleanupConnection: true, + sendDisconnectEvent: false, + cancelOperations: true, + reason: 'force-reconnect', + }); + + // Step 2: Force disconnect if connected if (peripheral.state === 'connected') { await new Promise(resolve => { peripheral.disconnect(() => { @@ -660,19 +1017,15 @@ async function forceReconnectPeripheral(peripheral: Peripheral, deviceId: string await wait(1000); } - // Step 2: Clear device state - connectedDevices.delete(deviceId); - deviceCharacteristics.delete(deviceId); - devicePacketStates.delete(deviceId); - subscribedDevices.delete(deviceId); - subscriptionOperations.delete(deviceId); + // Step 3: Clear any remaining listeners on the peripheral + peripheral.removeAllListeners(); - // Step 3: Re-establish connection + // Step 4: Re-establish connection with longer timeout await new Promise((resolve, reject) => { - peripheral.connect((error: string) => { + peripheral.connect((error: Error | undefined) => { if (error) { logger?.error('[NobleBLE] Force reconnect failed:', error); - reject(new Error(`Force reconnect failed: ${error}`)); + reject(new Error(`Force reconnect failed: ${error.message}`)); } else { logger?.info('[NobleBLE] Force reconnect successful'); connectedDevices.set(deviceId, peripheral); @@ -711,7 +1064,16 @@ async function connectAndDiscoverWithFreshScan(deviceId: string): Promise((resolve, reject) => { - freshPeripheral.connect((error: string) => { + freshPeripheral.connect((error: Error | undefined) => { if (error) { - reject(new Error(`Fresh peripheral connection failed: ${error}`)); + reject(new Error(`Fresh peripheral connection failed: ${error.message}`)); } else { connectedDevices.set(deviceId, freshPeripheral); resolve(); @@ -875,12 +1237,10 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis logger?.info( '[NobleBLE] Device has ongoing subscription operation:', ongoingOperation, - 'waiting...' + 'skip reconnect' ); - // Wait for ongoing operation to complete - await wait(100); - // Retry connection after waiting - return connectDevice(deviceId, webContents); + // 正在进行订阅操作,避免递归重连造成循环;直接返回,等待订阅流程完成 + return; } // Don't clean up notification state if device is already properly connected @@ -909,6 +1269,9 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis // Continue to re-setup the connection properly } + // Wait for the device to stabilize before proceeding + await wait(300); + // Discover services and characteristics with enhanced retry including fresh scan try { const characteristics = await connectAndDiscoverWithFreshScan(deviceId); @@ -931,12 +1294,12 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis // TypeScript type assertion - peripheral is guaranteed to be defined at this point const connectedPeripheral = peripheral as Peripheral; - connectedPeripheral.connect((error: string) => { + connectedPeripheral.connect(async (error: Error | undefined) => { clearTimeout(timeout); if (error) { logger?.error('[NobleBLE] Connection failed:', error); - reject(ERRORS.TypedError(HardwareErrorCode.BleConnectedError, error)); + reject(ERRORS.TypedError(HardwareErrorCode.BleConnectedError, error.message)); return; } @@ -946,22 +1309,20 @@ async function connectDevice(deviceId: string, webContents: WebContents): Promis // Set up unified disconnect listener setupDisconnectListener(connectedPeripheral, deviceId, webContents); - // Discover services and characteristics with enhanced retry including fresh scan - connectAndDiscoverWithFreshScan(deviceId) - .then(characteristics => { - deviceCharacteristics.set(deviceId, characteristics); - logger?.info('[NobleBLE] Device ready for communication:', deviceId); - resolve(); - }) - .catch(error => { - logger?.error( - '[NobleBLE] Service/characteristic discovery failed after all attempts:', - error - ); - // Disconnect on failure - connectedPeripheral.disconnect(); - reject(error); - }); + try { + const characteristics = await connectAndDiscoverWithFreshScan(deviceId); + deviceCharacteristics.set(deviceId, characteristics); + logger?.info('[NobleBLE] Device ready for communication:', deviceId); + resolve(); + } catch (discoveryError) { + logger?.error( + '[NobleBLE] Service/characteristic discovery failed after all attempts:', + discoveryError + ); + // Disconnect on failure + connectedPeripheral.disconnect(); + reject(discoveryError); + } }); }); } @@ -979,107 +1340,52 @@ async function disconnectDevice(deviceId: string): Promise { peripheral.disconnect(() => { // Clean up device state using unified function - cleanupDeviceState(deviceId); + cleanupDevice(deviceId, undefined, { + cleanupConnection: true, + sendDisconnectEvent: false, + cancelOperations: true, + reason: 'manual-disconnect', + }); resolve(); }); }); } -// Write data to device with chunking support -async function writeData(deviceId: string, hexData: string): Promise { +// Unsubscribe from notifications +async function unsubscribeNotifications(deviceId: string): Promise { const peripheral = connectedDevices.get(deviceId); const characteristics = deviceCharacteristics.get(deviceId); if (!peripheral || !characteristics) { - const error = `Device ${deviceId} not connected or characteristics not available`; - logger?.error('[NobleBLE] writeData failed:', error); - throw ERRORS.TypedError(HardwareErrorCode.TransportNotFound, error); - } - - const { write: writeCharacteristic } = characteristics; - - // Convert hex string to buffer - let buffer: Buffer; - try { - buffer = Buffer.from(hexData, 'hex'); - } catch (error) { - logger?.error('[NobleBLE] Hex conversion failed:', error); - throw ERRORS.TypedError( - HardwareErrorCode.BleWriteCharacteristicError, - `Failed to convert hex data: ${error}` - ); + return; } - logger?.info('[NobleBLE] Writing data:', { - deviceId, - dataLength: buffer.length, - firstBytes: buffer.subarray(0, 8).toString('hex'), - }); - - // If data is small enough, send directly - if (buffer.length <= BLE_PACKET_SIZE) { - await wait(5); - return new Promise((resolve, reject) => { - writeCharacteristic.write(buffer, true, (error: string) => { - if (error) { - logger?.error('[NobleBLE] Single packet write failed:', error); - reject(ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError, error)); - return; - } - // Record successful write time for pairing rejection detection - recentWriteOperations.set(deviceId, Date.now()); - resolve(); - }); - }); - } + const { notify: notifyCharacteristic } = characteristics; - // Split into chunks for large data - const chunks: Buffer[] = []; - let offset = 0; + logger?.info('[NobleBLE] Unsubscribing from notifications for device:', deviceId); - while (offset < buffer.length) { - const chunkSize = Math.min(BLE_PACKET_SIZE, buffer.length - offset); - const chunk = buffer.subarray(offset, offset + chunkSize); - chunks.push(chunk); - offset += chunkSize; - } + // 🔒 Set operation state to prevent race conditions + subscriptionOperations.set(deviceId, 'unsubscribing'); - logger?.info('[NobleBLE] Splitting into chunks:', chunks.length); + return new Promise(resolve => { + notifyCharacteristic.unsubscribe((error: Error | undefined) => { + if (error) { + logger?.error('[NobleBLE] Notification unsubscription failed:', error); + } else { + logger?.info('[NobleBLE] Notification unsubscription successful'); + } - // Helper function to write a single chunk - const writeChunk = (chunk: Buffer, chunkIndex: number): Promise => - new Promise((resolve, reject) => { - writeCharacteristic.write(chunk, false, (error: string) => { - if (error) { - logger?.error(`[NobleBLE] Chunk ${chunkIndex} write failed:`, error); - reject(ERRORS.TypedError(HardwareErrorCode.BleWriteCharacteristicError, error)); - return; - } - resolve(); - }); - }); + // Remove all listeners and clear subscription status + notifyCharacteristic.removeAllListeners('data'); + notificationCallbacks.delete(deviceId); + devicePacketStates.delete(deviceId); + subscribedDevices.delete(deviceId); - // Helper function for delay - const delay = (ms: number): Promise => - new Promise(resolve => { - setTimeout(() => resolve(), ms); + // 🔒 Clear operation state + subscriptionOperations.set(deviceId, 'idle'); + resolve(); }); - - // Write chunks sequentially - for (let i = 0; i < chunks.length; i++) { - const chunk = chunks[i]; - const chunkIndex = i + 1; - - await writeChunk(chunk, chunkIndex); - - // Small delay between chunks to avoid overwhelming the device - if (i < chunks.length - 1) { - await delay(CHUNK_WRITE_DELAY); - } - } - - // Record successful write time for pairing rejection detection - recentWriteOperations.set(deviceId, Date.now()); + }); } // Subscribe to notifications @@ -1092,7 +1398,7 @@ async function subscribeNotifications( if (!peripheral || !characteristics) { throw ERRORS.TypedError( - HardwareErrorCode.TransportNotFound, + HardwareErrorCode.BleCharacteristicNotFound, `Device ${deviceId} not connected or characteristics not available` ); } @@ -1100,6 +1406,19 @@ async function subscribeNotifications( const { notify: notifyCharacteristic } = characteristics; logger?.info('[NobleBLE] Subscribing to notifications for device:', deviceId); + logger?.info('[NobleBLE] Subscribe context', { + deviceId, + opStateBefore: subscriptionOperations.get(deviceId) || 'idle', + paired: false, + hasController: false, + }); + // If a subscription is already in progress, dedupe + const opState = subscriptionOperations.get(deviceId); + if (opState === 'subscribing') { + // Subscription in progress; update callback and return + notificationCallbacks.set(deviceId, callback); + return Promise.resolve(); + } // 🔒 Set operation state to prevent race conditions subscriptionOperations.set(deviceId, 'subscribing'); @@ -1127,9 +1446,11 @@ async function subscribeNotifications( // Clean up any existing listeners before subscribing if (notificationCallbacks.has(deviceId)) { logger?.info('[NobleBLE] Cleaning up previous notification listeners'); - notifyCharacteristic.removeAllListeners('data'); } + // 统一清理监听器(避免重复调用) + notifyCharacteristic.removeAllListeners('data'); + // Store callback for this device notificationCallbacks.set(deviceId, callback); @@ -1141,99 +1462,74 @@ async function subscribeNotifications( messageId: undefined, }); - return new Promise((resolve, reject) => { - // Subscribe to notifications only if not already subscribed - logger?.info('[NobleBLE] 🔄 Starting subscription process...', { deviceId }); - - notifyCharacteristic.subscribe((error: string) => { - if (error) { - logger?.error('[NobleBLE] ❌ Notification subscription failed:', error); - // 🔒 Clear operation state on error - subscriptionOperations.set(deviceId, 'idle'); - reject(ERRORS.TypedError(HardwareErrorCode.BleCharacteristicNotifyError, error)); - return; - } - - logger?.info('[NobleBLE] ✅ Notification subscription successful'); - subscribedDevices.set(deviceId, true); - - // 🔒 Clear operation state on success - subscriptionOperations.set(deviceId, 'idle'); - - // Set up data handler with robust packet reassembly - notifyCharacteristic.on('data', (data: Buffer) => { - const result = processNotificationData(deviceId, data); - - if (result.error) { - logger?.error('[NobleBLE] Packet processing error:', result.error); + // Helper: rebuild a clean application-layer subscription + async function rebuildAppSubscription( + deviceId: string, + notifyCharacteristic: Characteristic + ): Promise { + // 监听器已在上面清理,这里不需要重复清理 + await new Promise(resolve => { + notifyCharacteristic.unsubscribe(() => { + resolve(); + }); + }); + await new Promise((resolve, reject) => { + notifyCharacteristic.subscribe((error?: Error) => { + if (error) { + reject(error); return; } - - if (result.isComplete && result.completePacket) { - logger?.info('[NobleBLE] Packet complete:', { - deviceId, - length: result.completePacket.length / 2, - }); - callback(result.completePacket); - } + resolve(); }); - - resolve(); }); - }); -} - -// Unsubscribe from notifications -async function unsubscribeNotifications(deviceId: string): Promise { - const peripheral = connectedDevices.get(deviceId); - const characteristics = deviceCharacteristics.get(deviceId); - - if (!peripheral || !characteristics) { - return; - } - - const { notify: notifyCharacteristic } = characteristics; - logger?.info('[NobleBLE] Unsubscribing from notifications for device:', deviceId); - - // 🔒 Set operation state to prevent race conditions - subscriptionOperations.set(deviceId, 'unsubscribing'); - - return new Promise(resolve => { - notifyCharacteristic.unsubscribe((error: string) => { - if (error) { - logger?.error('[NobleBLE] Notification unsubscription failed:', error); - } else { - logger?.info('[NobleBLE] Notification unsubscription successful'); + notifyCharacteristic.on('data', (data: Buffer) => { + // Windows BLE 配对检测:收到任何数据都认为设备已配对 + if (!pairedDevices.has(deviceId)) { + pairedDevices.add(deviceId); + logger?.info('[NobleBLE] Device paired successfully', { deviceId }); } - // Remove all listeners and clear subscription status - notifyCharacteristic.removeAllListeners('data'); - notificationCallbacks.delete(deviceId); - devicePacketStates.delete(deviceId); - subscribedDevices.delete(deviceId); - - // 🔒 Clear operation state - subscriptionOperations.set(deviceId, 'idle'); - resolve(); + const result = processNotificationData(deviceId, data); + if (result.error) { + logger?.error('[NobleBLE] Packet processing error:', result.error); + return; + } + if (result.isComplete && result.completePacket) { + const appCb = notificationCallbacks.get(deviceId); + if (appCb) appCb(result.completePacket); + } }); - }); + } + + await rebuildAppSubscription(deviceId, notifyCharacteristic); + subscribedDevices.set(deviceId, true); + subscriptionOperations.set(deviceId, 'idle'); } +// (moved unsubscribeNotifications above) + // Setup IPC handlers export function setupNobleBleHandlers(webContents: WebContents): void { + // Use console.log for initial logging as electron-log might not be available yet. + console.log('[NobleBLE] Attempting to set up Noble BLE handlers.'); try { - console.log('NOBLE_VERSION_771'); + console.log('[NobleBLE] NOBLE_VERSION_771'); + // @ts-ignore – electron-log is only available at runtime // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require logger = require('electron-log') as Logger; + console.log('[NobleBLE] electron-log loaded successfully.'); + // @ts-ignore – electron is only available at runtime // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require const { ipcMain } = require('electron'); + console.log('[NobleBLE] electron.ipcMain loaded successfully.'); safeLog(logger, 'info', 'Setting up Noble BLE IPC handlers'); // Handle enumerate request + console.log(`[NobleBLE] Registering handler for: ${EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE}`); ipcMain.handle(EOneKeyBleMessageKeys.NOBLE_BLE_ENUMERATE, async () => { try { const devices = await enumerateDevices(); @@ -1282,7 +1578,8 @@ export function setupNobleBleHandlers(webContents: WebContents): void { ipcMain.handle( EOneKeyBleMessageKeys.NOBLE_BLE_WRITE, async (_event: IpcMainInvokeEvent, deviceId: string, hexData: string) => { - await writeData(deviceId, hexData); + logger?.info('[NobleBLE] IPC WRITE', { deviceId, len: hexData.length }); + await transmitHexDataToDevice(deviceId, hexData); } ); @@ -1305,6 +1602,27 @@ export function setupNobleBleHandlers(webContents: WebContents): void { } ); + // Handle cancel pairing: cleanup all connected devices + ipcMain.handle(EOneKeyBleMessageKeys.NOBLE_BLE_CANCEL_PAIRING, async () => { + const deviceIds = Array.from(connectedDevices.keys()); + logger?.info('[NobleBLE] Cancel pairing invoked', { + platform: process.platform, + deviceCount: deviceIds.length, + }); + + for (const deviceId of deviceIds) { + try { + // 取消订阅和断开连接(disconnectDevice 内部会调用 cleanupDevice) + await unsubscribeNotifications(deviceId).catch(() => {}); + await disconnectDevice(deviceId).catch(() => {}); + + // disconnectDevice 已经完成了所有清理工作,无需重复调用 cleanupDevice + } catch (e) { + logger?.error('[NobleBLE] Cancel pairing cleanup failed', { deviceId, error: e }); + } + } + }); + // Handle Bluetooth availability check request ipcMain.handle(EOneKeyBleMessageKeys.BLE_AVAILABILITY_CHECK, async () => { try { @@ -1326,30 +1644,31 @@ export function setupNobleBleHandlers(webContents: WebContents): void { webContents.on('destroyed', () => { safeLog(logger, 'info', 'Cleaning up Noble BLE handlers'); - // Disconnect all devices - connectedDevices.forEach(async (_peripheral, deviceId) => { - await disconnectDevice(deviceId); + // 1. 清理所有连接的设备(统一清理,避免重复) + const deviceIds = Array.from(connectedDevices.keys()); + deviceIds.forEach(deviceId => { + cleanupDevice(deviceId, undefined, { + cleanupConnection: true, + sendDisconnectEvent: false, + cancelOperations: true, + reason: 'app-quit', + }); }); - // Stop scanning + // 2. 停止扫描 stopScanning(); - // Remove persistent state listener + // 3. 清理 Noble 监听器 if (noble && persistentStateListener) { noble.removeListener('stateChange', persistentStateListener); persistentStateListener = null; } + cleanupNobleListeners(); - // Clear all caches using individual clear operations for better cleanup + // 4. 清理发现的设备缓存 discoveredDevices.clear(); - connectedDevices.clear(); - deviceCharacteristics.clear(); - notificationCallbacks.clear(); - devicePacketStates.clear(); - subscribedDevices.clear(); - // Clear operation states - subscriptionOperations.clear(); + safeLog(logger, 'info', 'Noble BLE cleanup completed'); }); safeLog(logger, 'info', 'Noble BLE IPC handlers setup completed'); diff --git a/packages/hd-transport-electron/src/types/noble-extended.ts b/packages/hd-transport-electron/src/types/noble-extended.ts index 8b4fb0bc7..caaae6fb8 100644 --- a/packages/hd-transport-electron/src/types/noble-extended.ts +++ b/packages/hd-transport-electron/src/types/noble-extended.ts @@ -3,7 +3,7 @@ * Supplements @types/noble with additional interfaces */ -import type { Peripheral, Characteristic } from '@abandonware/noble'; +import type { Peripheral, Characteristic } from '@stoprocent/noble'; // Device info interface for our API export interface DeviceInfo { diff --git a/packages/hd-transport-emulator/package.json b/packages/hd-transport-emulator/package.json index 21d52a9ac..38086f79c 100644 --- a/packages/hd-transport-emulator/package.json +++ b/packages/hd-transport-emulator/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/hd-transport-emulator", - "version": "1.1.10-alpha.2", + "version": "1.1.10", "description": "hardware emulator transport", "author": "OneKey", "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme", @@ -24,8 +24,8 @@ "url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues" }, "dependencies": { - "@onekeyfe/hd-shared": "1.1.10-alpha.2", - "@onekeyfe/hd-transport": "1.1.10-alpha.2", + "@onekeyfe/hd-shared": "1.1.10", + "@onekeyfe/hd-transport": "1.1.10", "axios": "^0.27.2", "secure-json-parse": "^4.0.0" } diff --git a/packages/hd-transport-http/package.json b/packages/hd-transport-http/package.json index 3295c7718..7741342aa 100644 --- a/packages/hd-transport-http/package.json +++ b/packages/hd-transport-http/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/hd-transport-http", - "version": "1.1.10-alpha.2", + "version": "1.1.10", "description": "hardware http transport", "author": "OneKey", "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme", @@ -24,8 +24,8 @@ "url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues" }, "dependencies": { - "@onekeyfe/hd-shared": "1.1.10-alpha.2", - "@onekeyfe/hd-transport": "1.1.10-alpha.2", + "@onekeyfe/hd-shared": "1.1.10", + "@onekeyfe/hd-transport": "1.1.10", "axios": "^0.27.2", "secure-json-parse": "^4.0.0" } diff --git a/packages/hd-transport-lowlevel/package.json b/packages/hd-transport-lowlevel/package.json index 06689cdbe..b6d4c0965 100644 --- a/packages/hd-transport-lowlevel/package.json +++ b/packages/hd-transport-lowlevel/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/hd-transport-lowlevel", - "version": "1.1.10-alpha.2", + "version": "1.1.10", "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme", "license": "MIT", "main": "dist/index.js", @@ -19,7 +19,7 @@ "lint:fix": "eslint . --fix" }, "dependencies": { - "@onekeyfe/hd-shared": "1.1.10-alpha.2", - "@onekeyfe/hd-transport": "1.1.10-alpha.2" + "@onekeyfe/hd-shared": "1.1.10", + "@onekeyfe/hd-transport": "1.1.10" } } diff --git a/packages/hd-transport-react-native/package.json b/packages/hd-transport-react-native/package.json index 93980293d..1eeae82fc 100644 --- a/packages/hd-transport-react-native/package.json +++ b/packages/hd-transport-react-native/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/hd-transport-react-native", - "version": "1.1.10-alpha.2", + "version": "1.1.10", "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme", "license": "MIT", "main": "dist/index.js", @@ -19,8 +19,8 @@ "lint:fix": "eslint . --fix" }, "dependencies": { - "@onekeyfe/hd-shared": "1.1.10-alpha.2", - "@onekeyfe/hd-transport": "1.1.10-alpha.2", + "@onekeyfe/hd-shared": "1.1.10", + "@onekeyfe/hd-transport": "1.1.10", "@onekeyfe/react-native-ble-utils": "^0.1.4", "react-native-ble-plx": "3.5.0" } diff --git a/packages/hd-transport-web-device/package.json b/packages/hd-transport-web-device/package.json index e176e9687..9f341d930 100644 --- a/packages/hd-transport-web-device/package.json +++ b/packages/hd-transport-web-device/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/hd-transport-web-device", - "version": "1.1.10-alpha.2", + "version": "1.1.10", "author": "OneKey", "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme", "license": "MIT", @@ -20,11 +20,11 @@ "lint:fix": "eslint . --fix" }, "dependencies": { - "@onekeyfe/hd-shared": "1.1.10-alpha.2", - "@onekeyfe/hd-transport": "1.1.10-alpha.2" + "@onekeyfe/hd-shared": "1.1.10", + "@onekeyfe/hd-transport": "1.1.10" }, "devDependencies": { - "@onekeyfe/hd-transport-electron": "1.1.10-alpha.2", + "@onekeyfe/hd-transport-electron": "1.1.10", "@types/w3c-web-usb": "^1.0.6", "@types/web-bluetooth": "^0.0.17" } diff --git a/packages/hd-transport/package.json b/packages/hd-transport/package.json index fab0d6fbb..b823eea68 100644 --- a/packages/hd-transport/package.json +++ b/packages/hd-transport/package.json @@ -1,7 +1,7 @@ { "name": "@onekeyfe/hd-transport", - "version": "1.1.10-alpha.2", - "description": "> TODO: description", + "version": "1.1.10", + "description": "Transport layer abstractions and utilities for OneKey hardware SDK.", "author": "OneKey", "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme", "license": "ISC", diff --git a/packages/hd-web-sdk/package.json b/packages/hd-web-sdk/package.json index 55064ed4e..b93065d15 100644 --- a/packages/hd-web-sdk/package.json +++ b/packages/hd-web-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/hd-web-sdk", - "version": "1.1.10-alpha.2", + "version": "1.1.10", "author": "OneKey", "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme", "license": "ISC", @@ -21,10 +21,10 @@ }, "dependencies": { "@onekeyfe/cross-inpage-provider-core": "^0.0.17", - "@onekeyfe/hd-core": "1.1.10-alpha.2", - "@onekeyfe/hd-shared": "1.1.10-alpha.2", - "@onekeyfe/hd-transport-http": "1.1.10-alpha.2", - "@onekeyfe/hd-transport-web-device": "1.1.10-alpha.2" + "@onekeyfe/hd-core": "1.1.10", + "@onekeyfe/hd-shared": "1.1.10", + "@onekeyfe/hd-transport-http": "1.1.10", + "@onekeyfe/hd-transport-web-device": "1.1.10" }, "devDependencies": { "@babel/plugin-proposal-optional-chaining": "^7.17.12", diff --git a/packages/shared/package.json b/packages/shared/package.json index f030cc469..3349c57e9 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -1,6 +1,6 @@ { "name": "@onekeyfe/hd-shared", - "version": "1.1.10-alpha.2", + "version": "1.1.10", "description": "Hardware SDK's shared tool library", "keywords": [ "Hardware-SDK", diff --git a/packages/shared/src/constants.ts b/packages/shared/src/constants.ts index 922adf050..b65463be2 100644 --- a/packages/shared/src/constants.ts +++ b/packages/shared/src/constants.ts @@ -39,6 +39,7 @@ export enum EOneKeyBleMessageKeys { NOBLE_BLE_SUBSCRIBE = '$onekey-noble-ble-subscribe', NOBLE_BLE_UNSUBSCRIBE = '$onekey-noble-ble-unsubscribe', NOBLE_BLE_NOTIFICATION = '$onekey-noble-ble-notification', + NOBLE_BLE_CANCEL_PAIRING = '$onekey-noble-ble-cancel-pairing', } export const ONEKEY_SERVICE_UUID = '00000001-0000-1000-8000-00805f9b34fb'; diff --git a/scripts/check-versions.js b/scripts/check-versions.js new file mode 100644 index 000000000..4ebd55acf --- /dev/null +++ b/scripts/check-versions.js @@ -0,0 +1,55 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +const fs = require('fs'); +const path = require('path'); + +const packagesDir = path.resolve(__dirname, '../packages'); + +function main() { + const versions = {}; + let firstVersion = null; + let hasError = false; + + const packageDirs = fs.readdirSync(packagesDir).filter(file => { + const filePath = path.join(packagesDir, file); + return fs.statSync(filePath).isDirectory(); + }); + + for (const pkg of packageDirs) { + const pkgJsonPath = path.join(packagesDir, pkg, 'package.json'); + if (fs.existsSync(pkgJsonPath)) { + try { + const pkgJson = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf-8')); + const { name, version } = pkgJson; + + if (name && version) { + versions[name] = version; + if (!firstVersion) { + firstVersion = version; + } + + if (version !== firstVersion) { + hasError = true; + } + } + } catch (e) { + console.error(`Error parsing ${pkgJsonPath}:`, e); + } + } + } + + if (hasError) { + console.error('❌ Error: Found inconsistent package versions.'); + console.log(' Please ensure all packages have the same version.'); + console.log('\n--- Version Report ---'); + for (const [name, version] of Object.entries(versions)) { + const marker = version === firstVersion ? '✅' : '❌'; + console.log(` ${marker} ${name}: ${version}`); + } + console.log('----------------------\n'); + process.exit(1); + } else { + console.log(`✅ All ${Object.keys(versions).length} packages are at version: ${firstVersion}`); + } +} + +main(); diff --git a/yarn.lock b/yarn.lock index 61fe0f1f5..cc260af33 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,30 +7,6 @@ resolved "https://registry.yarnpkg.com/7zip-bin/-/7zip-bin-5.2.0.tgz#7a03314684dd6572b7dfa89e68ce31d60286854d" integrity sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A== -"@abandonware/bluetooth-hci-socket@^0.5.3-11": - version "0.5.3-12" - resolved "https://registry.yarnpkg.com/@abandonware/bluetooth-hci-socket/-/bluetooth-hci-socket-0.5.3-12.tgz#0ff7132fc51c630cccc239c170c25cb85908c391" - integrity sha512-qo2cBoh94j6RPusaNXSLYI8Bzxuz01Bx3MD80a/QYzhHED/FZ6Y0k2w2kRbfIA2EEhFSCbXrBZDQlpilL4nbxA== - dependencies: - "@mapbox/node-pre-gyp" "^1.0.11" - debug "^4.3.4" - nan "^2.18.0" - node-gyp "^10.0.1" - optionalDependencies: - usb "^2.11.0" - -"@abandonware/noble@^1.9.2-26": - version "1.9.2-26" - resolved "https://registry.yarnpkg.com/@abandonware/noble/-/noble-1.9.2-26.tgz#e9160892ac1404209942c86acdadb8560de3a65b" - integrity sha512-dPx78rkxF+z2oR8KhVlNt3gHi5E6dMSkil6HaZuDanFlWAL/bP2oHqAtHrHZdqtKDnTiZUf7f93hpDkKWx36Lw== - dependencies: - debug "^4.3.4" - napi-thread-safe-callback "^0.0.6" - node-addon-api "^8.3.0" - node-gyp-build "^4.8.4" - optionalDependencies: - "@abandonware/bluetooth-hci-socket" "^0.5.3-11" - "@alephium/web3-wallet@^1.5.2": version "1.5.2" resolved "https://registry.yarnpkg.com/@alephium/web3-wallet/-/web3-wallet-1.5.2.tgz#d8111a5111623a85b2b3ac5280ce95756dee77bb" @@ -4356,21 +4332,6 @@ lodash "^4.17.15" tmp-promise "^3.0.2" -"@mapbox/node-pre-gyp@^1.0.11": - version "1.0.11" - resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa" - integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ== - dependencies: - detect-libc "^2.0.0" - https-proxy-agent "^5.0.0" - make-dir "^3.1.0" - node-fetch "^2.6.7" - nopt "^5.0.0" - npmlog "^5.0.1" - rimraf "^3.0.2" - semver "^7.3.5" - tar "^6.1.11" - "@mdx-js/loader@^3.1.0": version "3.1.0" resolved "https://registry.npmjs.org/@mdx-js/loader/-/loader-3.1.0.tgz#715fdab11d0c9567e45049c16a7d9c83cec88214" @@ -6159,6 +6120,102 @@ component-type "^1.2.1" join-component "^1.1.0" +"@serialport/binding-mock@10.2.2": + version "10.2.2" + resolved "https://registry.yarnpkg.com/@serialport/binding-mock/-/binding-mock-10.2.2.tgz#d322a8116a97806addda13c62f50e73d16125874" + integrity sha512-HAFzGhk9OuFMpuor7aT5G1ChPgn5qSsklTFOTUX72Rl6p0xwcSVsRtG/xaGp6bxpN7fI9D/S8THLBWbBgS6ldw== + dependencies: + "@serialport/bindings-interface" "^1.2.1" + debug "^4.3.3" + +"@serialport/bindings-cpp@12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@serialport/bindings-cpp/-/bindings-cpp-12.0.1.tgz#b7588a8b3e124e7679622ce980a7d8528e9f36a3" + integrity sha512-r2XOwY2dDvbW7dKqSPIk2gzsr6M6Qpe9+/Ngs94fNaNlcTRCV02PfaoDmRgcubpNVVcLATlxSxPTIDw12dbKOg== + dependencies: + "@serialport/bindings-interface" "1.2.2" + "@serialport/parser-readline" "11.0.0" + debug "4.3.4" + node-addon-api "7.0.0" + node-gyp-build "4.6.0" + +"@serialport/bindings-interface@1.2.2", "@serialport/bindings-interface@^1.2.1": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@serialport/bindings-interface/-/bindings-interface-1.2.2.tgz#c4ae9c1c85e26b02293f62f37435478d90baa460" + integrity sha512-CJaUd5bLvtM9c5dmO9rPBHPXTa9R2UwpkJ0wdh9JCYcbrPWsKz+ErvR0hBLeo7NPeiFdjFO4sonRljiw4d2XiA== + +"@serialport/parser-byte-length@12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@serialport/parser-byte-length/-/parser-byte-length-12.0.0.tgz#18b1db5d1b3b9d8e1153eb2ab3975ac5445b844a" + integrity sha512-0ei0txFAj+s6FTiCJFBJ1T2hpKkX8Md0Pu6dqMrYoirjPskDLJRgZGLqoy3/lnU1bkvHpnJO+9oJ3PB9v8rNlg== + +"@serialport/parser-cctalk@12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@serialport/parser-cctalk/-/parser-cctalk-12.0.0.tgz#f5c573b1ad2a9eed377aea9d70d264b36ca5dd5d" + integrity sha512-0PfLzO9t2X5ufKuBO34DQKLXrCCqS9xz2D0pfuaLNeTkyGUBv426zxoMf3rsMRodDOZNbFblu3Ae84MOQXjnZw== + +"@serialport/parser-delimiter@11.0.0": + version "11.0.0" + resolved "https://registry.yarnpkg.com/@serialport/parser-delimiter/-/parser-delimiter-11.0.0.tgz#e830c6bb49723d4446131277dc3243b502d09388" + integrity sha512-aZLJhlRTjSmEwllLG7S4J8s8ctRAS0cbvCpO87smLvl3e4BgzbVgF6Z6zaJd3Aji2uSiYgfedCdNc4L6W+1E2g== + +"@serialport/parser-delimiter@12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@serialport/parser-delimiter/-/parser-delimiter-12.0.0.tgz#43d3687f982829cc9b48ee0b21f2de80d0f19778" + integrity sha512-gu26tVt5lQoybhorLTPsH2j2LnX3AOP2x/34+DUSTNaUTzu2fBXw+isVjQJpUBFWu6aeQRZw5bJol5X9Gxjblw== + +"@serialport/parser-inter-byte-timeout@12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@serialport/parser-inter-byte-timeout/-/parser-inter-byte-timeout-12.0.0.tgz#1436f36fac92c950d290744e8ce56b2273a61d08" + integrity sha512-GnCh8K0NAESfhCuXAt+FfBRz1Cf9CzIgXfp7SdMgXwrtuUnCC/yuRTUFWRvuzhYKoAo1TL0hhUo77SFHUH1T/w== + +"@serialport/parser-packet-length@12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@serialport/parser-packet-length/-/parser-packet-length-12.0.0.tgz#3b5b8b47b6971c03dbc90ba61c0b8c5ec8bb0798" + integrity sha512-p1hiCRqvGHHLCN/8ZiPUY/G0zrxd7gtZs251n+cfNTn+87rwcdUeu9Dps3Aadx30/sOGGFL6brIRGK4l/t7MuQ== + +"@serialport/parser-readline@11.0.0": + version "11.0.0" + resolved "https://registry.yarnpkg.com/@serialport/parser-readline/-/parser-readline-11.0.0.tgz#c2c8c88e163d2abf7c0ffddbc1845336444e3454" + integrity sha512-rRAivhRkT3YO28WjmmG4FQX6L+KMb5/ikhyylRfzWPw0nSXy97+u07peS9CbHqaNvJkMhH1locp2H36aGMOEIA== + dependencies: + "@serialport/parser-delimiter" "11.0.0" + +"@serialport/parser-readline@12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@serialport/parser-readline/-/parser-readline-12.0.0.tgz#50e992004d7a84d5a12e0b016adb9021d3a72fbb" + integrity sha512-O7cywCWC8PiOMvo/gglEBfAkLjp/SENEML46BXDykfKP5mTPM46XMaX1L0waWU6DXJpBgjaL7+yX6VriVPbN4w== + dependencies: + "@serialport/parser-delimiter" "12.0.0" + +"@serialport/parser-ready@12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@serialport/parser-ready/-/parser-ready-12.0.0.tgz#193495e10c5a663029bce074d4f84cad173aab82" + integrity sha512-ygDwj3O4SDpZlbrRUraoXIoIqb8sM7aMKryGjYTIF0JRnKeB1ys8+wIp0RFMdFbO62YriUDextHB5Um5cKFSWg== + +"@serialport/parser-regex@12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@serialport/parser-regex/-/parser-regex-12.0.0.tgz#ffbb2b113f3a50d7760fcdff5a4dd0f213ab8166" + integrity sha512-dCAVh4P/pZrLcPv9NJ2mvPRBg64L5jXuiRxIlyxxdZGH4WubwXVXY/kBTihQmiAMPxbT3yshSX8f2+feqWsxqA== + +"@serialport/parser-slip-encoder@12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@serialport/parser-slip-encoder/-/parser-slip-encoder-12.0.0.tgz#362099d4cd170afe8583f1fa607176fd4fc14f1d" + integrity sha512-0APxDGR9YvJXTRfY+uRGhzOhTpU5akSH183RUcwzN7QXh8/1jwFsFLCu0grmAUfi+fItCkR+Xr1TcNJLR13VNA== + +"@serialport/parser-spacepacket@12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@serialport/parser-spacepacket/-/parser-spacepacket-12.0.0.tgz#347e34b0221f29eb252ebd341a0acfff920ad814" + integrity sha512-dozONxhPC/78pntuxpz/NOtVps8qIc/UZzdc/LuPvVsqCoJXiRxOg6ZtCP/W58iibJDKPZPAWPGYeZt9DJxI+Q== + +"@serialport/stream@12.0.0": + version "12.0.0" + resolved "https://registry.yarnpkg.com/@serialport/stream/-/stream-12.0.0.tgz#047f97f780d92ddfc04303cb625e0f7e5a01a2bf" + integrity sha512-9On64rhzuqKdOQyiYLYv2lQOh3TZU/D3+IWCR5gk0alPel2nwpp4YwDEGiUBfrQZEdQ6xww0PWkzqth4wqwX3Q== + dependencies: + "@serialport/bindings-interface" "1.2.2" + debug "4.3.4" + "@sideway/address@^4.1.3": version "4.1.4" resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0" @@ -6219,6 +6276,31 @@ dependencies: "@sinonjs/commons" "^1.7.0" +"@stoprocent/bluetooth-hci-socket@^2.2.3": + version "2.2.3" + resolved "https://registry.yarnpkg.com/@stoprocent/bluetooth-hci-socket/-/bluetooth-hci-socket-2.2.3.tgz#a47074514b840d9309d97beebcb6a7c05c9228e9" + integrity sha512-aQmCkEaybqH7B1K6k2oJoZTf03g3PzmZFfi9+NHDiNVPi2Mbet4Mf86gVNEnctaG5aS9743zEMxSunWOzpt3MQ== + dependencies: + async "^3.2.6" + debug "^4.3.7" + node-addon-api "^8.3.1" + node-gyp-build "^4.8.4" + patch-package "^8.0.0" + serialport "^12.0.0" + optionalDependencies: + usb "^2.14.0" + +"@stoprocent/noble@2.3.4": + version "2.3.4" + resolved "https://registry.yarnpkg.com/@stoprocent/noble/-/noble-2.3.4.tgz#6f6b7fc640e9ad697853846ab956ae47406f2ae6" + integrity sha512-Tq0DSSvkd3hRWROS/JqrvhgI9GcFaQlxWgn2SaZuvLXHM7OEtQ0jrOPuWtxf/vNF5CaS6JJeo5DzEy5vmGrJFQ== + dependencies: + debug "^4.3.7" + node-addon-api "^8.1.0" + node-gyp-build "^4.8.1" + optionalDependencies: + "@stoprocent/bluetooth-hci-socket" "^2.2.3" + "@substrate/ss58-registry@^1.50.0": version "1.50.0" resolved "https://registry.yarnpkg.com/@substrate/ss58-registry/-/ss58-registry-1.50.0.tgz#2d2a3d060cd4eadd200e4538078461ba73e13d6d" @@ -9016,6 +9098,11 @@ d3-selection "^3.0.0" d3-zoom "^3.0.0" +"@yarnpkg/lockfile@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== + JSONStream@^1.0.4: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -9029,11 +9116,6 @@ abab@^2.0.5: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - abbrev@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-2.0.0.tgz#cf59829b8b4f03f89dda2771cb7f3653828c89bf" @@ -9329,19 +9411,11 @@ aproba@^1.0.3: resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -"aproba@^1.0.3 || ^2.0.0", aproba@^2.0.0: +aproba@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== -are-we-there-yet@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz#372e0e7bd279d8e94c653aaa1f67200884bf3e1c" - integrity sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw== - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - are-we-there-yet@~1.1.2: version "1.1.7" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" @@ -9710,7 +9784,7 @@ async@^3.2.3: resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== -async@^3.2.4: +async@^3.2.4, async@^3.2.6: version "3.2.6" resolved "https://registry.npmjs.org/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== @@ -10347,6 +10421,7 @@ brace-expansion@^1.1.7, brace-expansion@^2.0.1, brace-expansion@^2.0.2: dependencies: balanced-match "^1.0.0" +braces@3.0.3, braces@^3.0.3, braces@~3.0.2: braces@3.0.3, braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" @@ -10986,10 +11061,15 @@ ci-info@^3.2.0, ci-info@^3.3.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.1.tgz#58331f6f472a25fe3a50a351ae3052936c2c7f32" integrity sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg== -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.6.tgz#8fe672437d01cd6c4561af5334e0cc50ff1955f7" - integrity sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw== +ci-info@^3.7.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cipher-base@1.0.5, cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.5" + resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.5.tgz#749f80731c7821e9a5fabd51f6998b696f296686" + integrity sha512-xq7ICKB4TMHUx7Tz1L9O2SGKOhYMOTR32oir45Bq28/AQTpHogKgHcoYFSdRbMtddl+ozNXfXY9jWcgYKmde0w== dependencies: inherits "^2.0.4" safe-buffer "^5.2.1" @@ -11199,11 +11279,6 @@ color-string@^1.9.0: color-name "^1.0.0" simple-swizzle "^0.2.2" -color-support@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - color2k@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/color2k/-/color2k-2.0.3.tgz#a771244f6b6285541c82aa65ff0a0c624046e533" @@ -11439,7 +11514,7 @@ console-browserify@^1.2.0: resolved "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== -console-control-strings@^1.0.0, console-control-strings@^1.1.0, console-control-strings@~1.1.0: +console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= @@ -12108,7 +12183,7 @@ debug@^3.1.0, debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.0, debug@^4.4.0, debug@^4.4.1: +debug@^4.0.0, debug@^4.3.7, debug@^4.4.0, debug@^4.4.1: version "4.4.1" resolved "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== @@ -12362,11 +12437,6 @@ detect-libc@^1.0.3: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== -detect-libc@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8" - integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA== - detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -14438,7 +14508,7 @@ find-value@^1.0.12: resolved "https://registry.yarnpkg.com/find-value/-/find-value-1.0.12.tgz#68b6cec84e5b2d51272965e0bf09b26c9159c26e" integrity sha512-OCpo8LTk8eZ2sdDCwbU2Lc3ivYsdM6yod6jP2jHcNEFcjPhkgH0+POzTIol7xx1LZgtbI5rkO5jqxsG5MWtPjQ== -find-yarn-workspace-root@~2.0.0: +find-yarn-workspace-root@^2.0.0, find-yarn-workspace-root@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ== @@ -14712,21 +14782,6 @@ fwd-stream@^1.0.4: dependencies: readable-stream "~1.0.26-4" -gauge@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-3.0.2.tgz#03bf4441c044383908bcfa0656ad91803259b395" - integrity sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q== - dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.2" - console-control-strings "^1.0.0" - has-unicode "^2.0.1" - object-assign "^4.1.1" - signal-exit "^3.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.2" - gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -17410,6 +17465,17 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= +json-stable-stringify@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz#8903cfac42ea1a0f97f35d63a4ce0518f0cc6a70" + integrity sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + isarray "^2.0.5" + jsonify "^0.0.1" + object-keys "^1.1.1" + json-stringify-safe@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -17443,6 +17509,11 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" +jsonify@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978" + integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg== + jsonparse@^1.2.0, jsonparse@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -17498,6 +17569,13 @@ kind-of@^6.0.2, kind-of@^6.0.3: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +klaw-sync@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" + integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== + dependencies: + graceful-fs "^4.1.11" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -19468,11 +19546,6 @@ mz@^2.7.0: object-assign "^4.0.1" thenify-all "^1.0.0" -nan@^2.18.0: - version "2.22.2" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.2.tgz#6b504fd029fb8f38c0990e52ad5c26772fdacfbb" - integrity sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ== - nanoassert@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/nanoassert/-/nanoassert-2.0.0.tgz#a05f86de6c7a51618038a620f88878ed1e490c09" @@ -19493,11 +19566,6 @@ napi-postinstall@^0.3.0: resolved "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.0.tgz#888e51d1fb500e86dcf6ace1baccdbb377e654ce" integrity sha512-M7NqKyhODKV1gRLdkwE7pDsZP2/SC2a2vHkOYh9MCpKMbWVfyVfUw5MaH83Fv6XMjxr5jryUp3IDDL9rlxsTeA== -napi-thread-safe-callback@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/napi-thread-safe-callback/-/napi-thread-safe-callback-0.0.6.tgz#ef86a149b5312e480f74e89a614e6d9e3b17b456" - integrity sha512-X7uHCOCdY4u0yamDxDrv3jF2NtYc8A1nvPzBQgvpoSX+WB3jAe2cVNsY448V1ucq7Whf9Wdy02HEUoLW5rJKWg== - natural-compare-lite@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" @@ -19556,16 +19624,26 @@ node-abort-controller@^3.1.1: resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== +node-addon-api@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.0.0.tgz#8136add2f510997b3b94814f4af1cce0b0e3962e" + integrity sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA== + node-addon-api@^1.6.3: version "1.7.2" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.2.tgz#3df30b95720b53c24e59948b49532b662444f54d" integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg== -node-addon-api@^8.0.0, node-addon-api@^8.3.0: +node-addon-api@^8.0.0: version "8.4.0" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.4.0.tgz#8cbc68ee1c216368921a8f63038a23a39cd8ba44" integrity sha512-D9DI/gXHvVmjHS08SVch0Em8G5S1P+QWtU31appcKT/8wFSPRcdHadIFSAntdMMVM5zz+/DL+bL/gz3UDppqtg== +node-addon-api@^8.1.0, node-addon-api@^8.3.1: + version "8.5.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-8.5.0.tgz#c91b2d7682fa457d2e1c388150f0dff9aafb8f3f" + integrity sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A== + node-dir@^0.1.17: version "0.1.17" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" @@ -19585,12 +19663,17 @@ node-forge@^1, node-forge@^1.2.1, node-forge@^1.3.1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== -node-gyp-build@^4.5.0, node-gyp-build@^4.8.4: +node-gyp-build@4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" + integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== + +node-gyp-build@^4.5.0, node-gyp-build@^4.8.1, node-gyp-build@^4.8.4: version "4.8.4" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.4.tgz#8a70ee85464ae52327772a90d66c6077a900cfc8" integrity sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ== -node-gyp@10.0.1, node-gyp@^10.0.1, node-gyp@^5.0.2, node-gyp@^7.1.0: +node-gyp@10.0.1, node-gyp@^5.0.2, node-gyp@^7.1.0: version "10.0.1" resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-10.0.1.tgz#205514fc19e5830fa991e4a689f9e81af377a966" integrity sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg== @@ -19634,13 +19717,6 @@ node-stream-zip@^1.9.1: resolved "https://registry.yarnpkg.com/node-stream-zip/-/node-stream-zip-1.15.0.tgz#158adb88ed8004c6c49a396b50a6a5de3bca33ea" integrity sha512-LN4fydt9TqhZhThkZIVQnF9cwjU3qmUH9h78Mx/K7d3VvfRqqwthLwJEUOEL0QPZ0XQmNN7be5Ggit5+4dq3Bw== -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== - dependencies: - abbrev "1" - nopt@^7.0.0: version "7.2.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-7.2.1.tgz#1cac0eab9b8e97c9093338446eddd40b2c8ca1e7" @@ -19812,16 +19888,6 @@ npmlog@^4.1.2: gauge "~2.7.3" set-blocking "~2.0.0" -npmlog@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-5.0.1.tgz#f06678e80e29419ad67ab964e0fa69959c1eb8b0" - integrity sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw== - dependencies: - are-we-there-yet "^2.0.0" - console-control-strings "^1.1.0" - gauge "^3.0.0" - set-blocking "^2.0.0" - nth-check@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d" @@ -20085,7 +20151,7 @@ open@^6.2.0: dependencies: is-wsl "^1.1.0" -open@^7.0.3: +open@^7.0.3, open@^7.4.2: version "7.4.2" resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q== @@ -20298,7 +20364,7 @@ p-reduce@^2.0.0, p-reduce@^2.1.0: resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== -p-retry@^4.5.0: +p-retry@^4.5.0, p-retry@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== @@ -20481,6 +20547,27 @@ password-prompt@^1.0.4: ansi-escapes "^3.1.0" cross-spawn "^6.0.5" +patch-package@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61" + integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA== + 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 "^9.0.0" + json-stable-stringify "^1.0.2" + klaw-sync "^6.0.0" + minimist "^1.2.6" + open "^7.4.2" + rimraf "^2.6.3" + semver "^7.5.3" + slash "^2.0.0" + tmp "^0.0.33" + yaml "^2.2.2" + path-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" @@ -22897,6 +22984,26 @@ serialize-javascript@^6.0.2: dependencies: randombytes "^2.1.0" +serialport@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/serialport/-/serialport-12.0.0.tgz#136f0976042f57a2e99e886221a2109934531602" + integrity sha512-AmH3D9hHPFmnF/oq/rvigfiAouAKyK/TjnrkwZRYSFZxNggJxwvbAbfYrLeuvq7ktUdhuHdVdSjj852Z55R+uA== + dependencies: + "@serialport/binding-mock" "10.2.2" + "@serialport/bindings-cpp" "12.0.1" + "@serialport/parser-byte-length" "12.0.0" + "@serialport/parser-cctalk" "12.0.0" + "@serialport/parser-delimiter" "12.0.0" + "@serialport/parser-inter-byte-timeout" "12.0.0" + "@serialport/parser-packet-length" "12.0.0" + "@serialport/parser-readline" "12.0.0" + "@serialport/parser-ready" "12.0.0" + "@serialport/parser-regex" "12.0.0" + "@serialport/parser-slip-encoder" "12.0.0" + "@serialport/parser-spacepacket" "12.0.0" + "@serialport/stream" "12.0.0" + debug "4.3.4" + serve-index@^1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" @@ -23008,7 +23115,7 @@ sf-symbols-typescript@^1.0.0: resolved "https://registry.yarnpkg.com/sf-symbols-typescript/-/sf-symbols-typescript-1.0.0.tgz#94e9210bf27e7583f9749a0d07bd4f4937ea488f" integrity sha512-DkS7q3nN68dEMb4E18HFPDAvyrjDZK9YAQQF2QxeFu9gp2xRDXFMF8qLJ1EmQ/qeEGQmop4lmMM1WtYJTIcCMw== -sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: +sha.js@2.4.12, sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: version "2.4.12" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.12.tgz#eb8b568bf383dfd1867a32c3f2b74eb52bdbf23f" integrity sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w== @@ -23137,6 +23244,11 @@ sisteransi@^1.0.5: resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -24350,7 +24462,7 @@ tmp-promise@^3.0.2: tmp@0.2.4, tmp@^0.0.33, tmp@^0.2.0: version "0.2.4" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz#c6db987a2ccc97f812f17137b36af2b6521b0d13" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.4.tgz#c6db987a2ccc97f812f17137b36af2b6521b0d13" integrity sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ== tmpl@1.0.5: @@ -25048,10 +25160,10 @@ url@^0.11.4: punycode "^1.4.1" qs "^6.12.3" -usb@^2.11.0: - version "2.15.0" - resolved "https://registry.yarnpkg.com/usb/-/usb-2.15.0.tgz#50b9310b51e35e967279278be0a4a5eff70d4429" - integrity sha512-BA9r7PFxyYp99wps1N70lIqdPb2Utcl2KkWohDtWUmhDBeM5hDH1Zl/L/CZvWxd5W3RUCNm1g+b+DEKZ6cHzqg== +usb@^2.14.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/usb/-/usb-2.16.0.tgz#6c7a043d2b6305859974a92c30c2fa0d1285bbd3" + integrity sha512-jD88fvzDViMDH5KmmNJgzMBDj/95bDTt6+kBNaNxP4G98xUTnDMiLUY2CYmToba6JAFhM9VkcaQuxCNRLGR7zg== dependencies: "@types/w3c-web-usb" "^1.0.6" node-addon-api "^8.0.0" @@ -25779,7 +25891,7 @@ which@^4.0.0: dependencies: isexe "^3.1.1" -wide-align@^1.1.0, wide-align@^1.1.2: +wide-align@^1.1.0: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== @@ -26027,6 +26139,11 @@ yaml@^2.2.1: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== +yaml@^2.2.2: + version "2.8.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79" + integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw== + yaml@^2.3.4: version "2.8.0" resolved "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz#15f8c9866211bdc2d3781a0890e44d4fa1a5fff6"