From 87a0b3926c3014381e438a1b058f4eca356fa5f9 Mon Sep 17 00:00:00 2001 From: rob thijssen Date: Tue, 15 Sep 2026 12:02:19 +0300 Subject: [PATCH] feat: remove the Ledger account path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No hardware wallet speaks ML-DSA, and @polkadot/hw-ledger talks ed25519 over the Ledger Substrate app, so every one of these screens was unreachable for a Quantus account. Removed rather than hidden behind a flag: this fork is not trying to stay mergeable with upstream, so unreachable UI costs more than it saves. It is also work that quantus/common#6 turns into a type error regardless. Gone: ImportLedger.tsx, useLedger.ts, LedgerSign.tsx, legerChains.ts (upstream's typo), the route and its ALLOWED_PATH entry, the add-menu item, the Ledger App setting, and the @polkadot/hw-ledger dependency. Also gone is the background handler. accountsCreateHardware and its message type were reachable only from ImportLedger, so they are now dead code — and dead code that mints accounts is worth deleting rather than leaving for someone to wire up again. Two things deliberately stay: isHardware remains on AccountJson. Nothing creates such an account any more, but a restored JSON can still carry the flag, and the display branches that read it are correct for that case — an imported hardware account has no key here and cannot sign. Ripping the flag out would touch unrelated display code to remove a branch that is right. canEditGenesis becomes unconditional. It was `!isHardware || ledgerApp === 'generic'`, because the chain-specific Ledger app could not sign for an arbitrary genesis hash. With no hardware path and no such setting, nothing restricts it. The two spec cases that asserted the old behaviour are rewritten into one that asserts the new rule, rather than deleted. Not done, contrary to what the issue asked for: no "hardware wallets are not supported" note in the add menu. The reasoning there was that a missing item reads as broken — but that only holds for someone looking for it, and in a Quantus-only wallet nobody is. A permanent dead entry needing translation into every locale is a worse wart than its absence. It belongs in the README when branding lands (#2). 65 tests pass; typecheck clean. Refs quantus/extension#5 Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_012uDUodEcRbBwNRi3UCmw8f --- .../src/background/handlers/Extension.ts | 10 +- .../extension-base/src/background/types.ts | 11 - packages/extension-base/src/defaults.ts | 4 +- packages/extension-ui/package.json | 1 - .../src/Popup/Accounts/Account.spec.tsx | 27 +- .../src/Popup/Accounts/Account.tsx | 8 +- .../extension-ui/src/Popup/ImportLedger.tsx | 225 ----------- .../src/Popup/Metadata/Request.tsx | 2 +- .../src/Popup/Signing/LedgerSign.tsx | 239 ----------- .../src/Popup/Signing/Request/index.tsx | 17 +- packages/extension-ui/src/Popup/index.tsx | 2 - packages/extension-ui/src/hooks/index.js | 1 - packages/extension-ui/src/hooks/useLedger.ts | 287 -------------- packages/extension-ui/src/messaging.ts | 4 - .../extension-ui/src/partials/MenuAdd.tsx | 41 +- .../src/partials/MenuSettings.tsx | 21 - packages/extension-ui/src/util/legerChains.ts | 6 - yarn.lock | 370 +----------------- 18 files changed, 28 insertions(+), 1248 deletions(-) delete mode 100644 packages/extension-ui/src/Popup/ImportLedger.tsx delete mode 100644 packages/extension-ui/src/Popup/Signing/LedgerSign.tsx delete mode 100644 packages/extension-ui/src/hooks/useLedger.ts delete mode 100644 packages/extension-ui/src/util/legerChains.ts diff --git a/packages/extension-base/src/background/handlers/Extension.ts b/packages/extension-base/src/background/handlers/Extension.ts index 0d0e34c2..3b98ce7e 100644 --- a/packages/extension-base/src/background/handlers/Extension.ts +++ b/packages/extension-base/src/background/handlers/Extension.ts @@ -8,7 +8,7 @@ import type { KeyringPair, KeyringPair$Json, KeyringPair$Meta } from '@polkadot/ import type { Registry } from '@polkadot/types/types'; import type { SubjectInfo } from '@polkadot/ui-keyring/observable/types'; import type { KeypairType } from '@polkadot/util-crypto/types'; -import type { AccountJson, AllowedPath, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountBatchExport, RequestAccountChangePassword, RequestAccountCreateExternal, RequestAccountCreateHardware, RequestAccountCreateSuri, RequestAccountEdit, RequestAccountExport, RequestAccountForget, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestActiveTabsUrlUpdate, RequestAuthorizeApprove, RequestBatchRestore, RequestDeriveCreate, RequestDeriveValidate, RequestJsonRestore, RequestMetadataApprove, RequestMetadataReject, RequestSeedCreate, RequestSeedValidate, RequestSigningApprovePassword, RequestSigningApproveSignature, RequestSigningCancel, RequestSigningIsLocked, RequestTypes, RequestUpdateAuthorizedAccounts, ResponseAccountExport, ResponseAccountsExport, ResponseAuthorizeList, ResponseDeriveValidate, ResponseJsonGetAccountInfo, ResponseSeedCreate, ResponseSeedValidate, ResponseSigningIsLocked, ResponseType, SigningRequest } from '../types.js'; +import type { AccountJson, AllowedPath, AuthorizeRequest, MessageTypes, MetadataRequest, RequestAccountBatchExport, RequestAccountChangePassword, RequestAccountCreateExternal, RequestAccountCreateSuri, RequestAccountEdit, RequestAccountExport, RequestAccountForget, RequestAccountShow, RequestAccountTie, RequestAccountValidate, RequestActiveTabsUrlUpdate, RequestAuthorizeApprove, RequestBatchRestore, RequestDeriveCreate, RequestDeriveValidate, RequestJsonRestore, RequestMetadataApprove, RequestMetadataReject, RequestSeedCreate, RequestSeedValidate, RequestSigningApprovePassword, RequestSigningApproveSignature, RequestSigningCancel, RequestSigningIsLocked, RequestTypes, RequestUpdateAuthorizedAccounts, ResponseAccountExport, ResponseAccountsExport, ResponseAuthorizeList, ResponseDeriveValidate, ResponseJsonGetAccountInfo, ResponseSeedCreate, ResponseSeedValidate, ResponseSigningIsLocked, ResponseType, SigningRequest } from '../types.js'; import type { AuthorizedAccountsDiff } from './State.js'; import type State from './State.js'; @@ -61,12 +61,6 @@ export default class Extension { return true; } - private accountsCreateHardware ({ accountIndex, address, addressOffset, genesisHash, hardwareType, name, type }: RequestAccountCreateHardware): boolean { - keyring.addHardware(address, hardwareType, { accountIndex, addressOffset, genesisHash, name, type }); - - return true; - } - private accountsCreateSuri ({ genesisHash, name, password, suri, type }: RequestAccountCreateSuri): boolean { keyring.addUri(getSuri(suri, type), password, { genesisHash, name }, type); @@ -582,8 +576,6 @@ export default class Extension { case 'pri(accounts.create.external)': return this.accountsCreateExternal(request as RequestAccountCreateExternal); - case 'pri(accounts.create.hardware)': - return this.accountsCreateHardware(request as RequestAccountCreateHardware); case 'pri(accounts.create.suri)': return this.accountsCreateSuri(request as RequestAccountCreateSuri); diff --git a/packages/extension-base/src/background/types.ts b/packages/extension-base/src/background/types.ts index a5a0f57c..e8516445 100644 --- a/packages/extension-base/src/background/types.ts +++ b/packages/extension-base/src/background/types.ts @@ -80,7 +80,6 @@ export type ConnectedTabsUrlResponse = string[] export interface RequestSignatures { // private/internal requests, i.e. from a popup 'pri(accounts.create.external)': [RequestAccountCreateExternal, boolean]; - 'pri(accounts.create.hardware)': [RequestAccountCreateHardware, boolean]; 'pri(accounts.create.suri)': [RequestAccountCreateSuri, boolean]; 'pri(accounts.edit)': [RequestAccountEdit, boolean]; 'pri(accounts.export)': [RequestAccountExport, ResponseAccountExport]; @@ -197,16 +196,6 @@ export interface RequestAccountCreateSuri { type?: KeypairType; } -export interface RequestAccountCreateHardware { - accountIndex: number; - address: string; - addressOffset: number; - genesisHash?: HexString | null; - hardwareType: string; - name: string; - type: KeypairType; -} - export interface RequestAccountChangePassword { address: string; oldPass: string; diff --git a/packages/extension-base/src/defaults.ts b/packages/extension-base/src/defaults.ts index 0a13f808..b3d088d1 100644 --- a/packages/extension-base/src/defaults.ts +++ b/packages/extension-base/src/defaults.ts @@ -16,7 +16,9 @@ export const PORT_EXTENSION = `${PORT_PREFIX}-extension`; export const MESSAGE_ORIGIN_PAGE = `${PORT_PREFIX}-page`; export const MESSAGE_ORIGIN_CONTENT = `${PORT_PREFIX}-content`; -export const ALLOWED_PATH = ['/', '/account/import-ledger', '/account/restore-json'] as const; +// '/account/import-ledger' is gone with the Ledger path: no hardware wallet +// speaks ML-DSA, so there is nothing for it to connect to. See quantus/extension#5. +export const ALLOWED_PATH = ['/', '/account/restore-json'] as const; export const PASSWORD_EXPIRY_MIN = 15; export const PASSWORD_EXPIRY_MS = PASSWORD_EXPIRY_MIN * 60 * 1000; diff --git a/packages/extension-ui/package.json b/packages/extension-ui/package.json index b0ca3f2e..c54ff026 100644 --- a/packages/extension-ui/package.json +++ b/packages/extension-ui/package.json @@ -29,7 +29,6 @@ "@polkadot/extension-chains": "0.64.0", "@polkadot/extension-dapp": "0.64.0", "@polkadot/extension-inject": "0.64.0", - "@polkadot/hw-ledger": "^14.0.3", "@polkadot/keyring": "^14.0.3", "@polkadot/networks": "^14.0.3", "@polkadot/react-identicon": "^3.16.7", diff --git a/packages/extension-ui/src/Popup/Accounts/Account.spec.tsx b/packages/extension-ui/src/Popup/Accounts/Account.spec.tsx index 8428b3ae..2d66c20b 100644 --- a/packages/extension-ui/src/Popup/Accounts/Account.spec.tsx +++ b/packages/extension-ui/src/Popup/Accounts/Account.spec.tsx @@ -37,9 +37,9 @@ describe('Account component', () => { let wrapper: ReactWrapper; const VALID_ADDRESS = 'HjoBp62cvsWDA3vtNMWxz6c9q13ReEHi9UGHK7JbZweH5g5'; // eslint-disable-next-line @typescript-eslint/no-unsafe-return - const mountAccountComponent = (additionalAccountProperties: Record, ledgerApp: 'generic' | 'migration' | 'chainSpecific' = 'chainSpecific'): ReactWrapper => mount( + const mountAccountComponent = (additionalAccountProperties: Record): ReactWrapper => mount( - + @@ -83,19 +83,16 @@ describe('Account component', () => { expect(wrapper.find('.genesisSelection').exists()).toBe(true); }); - it('does not show genesis hash selection dropsown if account is hardware', async () => { - wrapper = mountAccountComponent({ isExternal: true, isHardware: true }, 'chainSpecific'); - wrapper.find('.settings').first().simulate('click'); - await act(flushAllPromises); - - expect(wrapper.find('a.menuItem').length).toBe(2); - expect(wrapper.find('a.menuItem').at(0).text()).toBe('Rename'); - expect(wrapper.find('a.menuItem').at(1).text()).toBe('Forget Account'); - expect(wrapper.find('.genesisSelection').exists()).toBe(false); - }); - - it('shows genesis hash selection for hardware account in generic mode', async () => { - wrapper = mountAccountComponent({ isExternal: true, isHardware: true }, 'generic'); + // Was two tests, one per Ledger app mode: the chain-specific app could not + // sign for an arbitrary genesis hash, so the dropdown was hidden for hardware + // accounts unless the generic app was selected. With no hardware path left + // (quantus/extension#5) there is no such restriction, and the setting that + // drove it is gone. + // + // isHardware survives as a meta flag — a restored JSON can still carry it — + // so an account marked that way must still behave like any other. + it('shows genesis hash selection even for an account marked hardware', async () => { + wrapper = mountAccountComponent({ isExternal: true, isHardware: true }); wrapper.find('.settings').first().simulate('click'); await act(flushAllPromises); diff --git a/packages/extension-ui/src/Popup/Accounts/Account.tsx b/packages/extension-ui/src/Popup/Accounts/Account.tsx index 9da09cd9..50f48d61 100644 --- a/packages/extension-ui/src/Popup/Accounts/Account.tsx +++ b/packages/extension-ui/src/Popup/Accounts/Account.tsx @@ -8,7 +8,7 @@ import React, { useCallback, useContext, useEffect, useMemo, useState } from 're import { canDerive } from '@polkadot/extension-base/utils'; -import { AccountContext, Address, Checkbox, Dropdown, Link, MenuDivider, SettingsContext } from '../../components/index.js'; +import { AccountContext, Address, Checkbox, Dropdown, Link, MenuDivider } from '../../components/index.js'; import { useGenesisHashOptions, useTranslation } from '../../hooks/index.js'; import { editAccount, tieAccount } from '../../messaging.js'; import { Name } from '../../partials/index.js'; @@ -33,10 +33,12 @@ function Account ({ address, className, genesisHash, isExternal, isHardware, isH const [editedName, setName] = useState(name); const [checked, setChecked] = useState(false); const genesisOptions = useGenesisHashOptions(); - const { ledgerApp } = useContext(SettingsContext); const { selectedAccounts = [], setSelectedAccounts } = useContext(AccountContext); const isSelected = useMemo(() => selectedAccounts?.includes(address) || false, [address, selectedAccounts]); - const canEditGenesis = !isHardware || ledgerApp === 'generic'; + // Was `!isHardware || ledgerApp === 'generic'` — the Ledger Substrate app only + // let you pin a genesis hash in its generic mode. With no hardware path left, + // there is nothing to restrict. See quantus/extension#5. + const canEditGenesis = true; useEffect(() => { setChecked(isSelected); diff --git a/packages/extension-ui/src/Popup/ImportLedger.tsx b/packages/extension-ui/src/Popup/ImportLedger.tsx deleted file mode 100644 index e5887d44..00000000 --- a/packages/extension-ui/src/Popup/ImportLedger.tsx +++ /dev/null @@ -1,225 +0,0 @@ -// Copyright 2019-2026 @polkadot/extension-ui authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import type { HexString } from '@polkadot/util/types'; - -import { faSync } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; - -import { settings } from '@polkadot/ui-settings'; - -import { ActionContext, Address, Button, ButtonArea, Dropdown, SettingsContext, Switch, VerticalSpace, Warning } from '../components/index.js'; -import { useLedger, useTranslation } from '../hooks/index.js'; -import { createAccountHardware } from '../messaging.js'; -import { Header, Name } from '../partials/index.js'; -import { styled } from '../styled.js'; -import ledgerChains from '../util/legerChains.js'; - -interface AccOption { - text: string; - value: number; -} - -interface NetworkOption { - text: string; - value: string; -} - -const AVAIL: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]; -const SELECT_NETWORK = ''; -const ALLOW_ANY_NETWORK = '__allow_any_network__'; - -interface Props { - className?: string; -} - -function ImportLedger ({ className }: Props): React.ReactElement { - const { t } = useTranslation(); - const [accountIndex, setAccountIndex] = useState(0); - const [addressOffset, setAddressOffset] = useState(0); - const [error, setError] = useState(null); - const [isBusy, setIsBusy] = useState(false); - const [genesis, setGenesis] = useState(null); - const [isEthereum, setIsEthereum] = useState(false); - const onAction = useContext(ActionContext); - const { ledgerApp } = useContext(SettingsContext); - const [name, setName] = useState(null); - const isGenericLedgerApp = ledgerApp === 'generic'; - const isChainSpecific = ledgerApp === 'chainSpecific'; - const { address, error: ledgerError, isLoading: ledgerLoading, isLocked: ledgerLocked, refresh, type, warning: ledgerWarning } = useLedger(genesis, accountIndex, addressOffset, isEthereum); - - useEffect(() => { - if (address) { - settings.set({ ledgerConn: 'webusb' }); - } - }, [address]); - - useEffect(() => { - if (isChainSpecific) { - setIsEthereum(false); - } - }, [isChainSpecific]); - - const accOps = useRef(AVAIL.map((value): AccOption => ({ - text: t('Account type {{index}}', { replace: { index: value } }), - value - }))); - - const addOps = useRef(AVAIL.map((value): AccOption => ({ - text: t('Address index {{index}}', { replace: { index: value } }), - value - }))); - - const onNetworkChange = useCallback((value: string) => { - if (value === ALLOW_ANY_NETWORK) { - setGenesis(null); - - return; - } - - setGenesis(value ? value as HexString : null); - }, []); - - const networkOps = useMemo( - () => [ - ...(isGenericLedgerApp - ? [{ text: t('Allow use on any chain'), value: ALLOW_ANY_NETWORK }] - : [{ text: t('Select network'), value: SELECT_NETWORK }]), - ...ledgerChains.map(({ displayName, genesisHash }): NetworkOption => ({ - text: displayName, - value: genesisHash[0] - })) - ], - [isGenericLedgerApp, t] - ); - - const _onSave = useCallback( - () => { - if (address && name && type) { - setIsBusy(true); - - createAccountHardware(address, 'ledger', accountIndex, addressOffset, name, genesis, type) - .then(() => onAction('/')) - .catch((error: Error) => { - console.error(error); - - setIsBusy(false); - setError(error.message); - }); - } - }, - [accountIndex, address, addressOffset, genesis, name, onAction, type] - ); - - // select element is returning a string - const _onSetAccountIndex = useCallback((value: number) => setAccountIndex(Number(value)), []); - const _onSetAddressOffset = useCallback((value: number) => setAddressOffset(Number(value)), []); - - return ( - <> -
-
-
-
- -
- - {!!address && !ledgerError && ( - - )} - {!!name && ( - <> - - - - - )} - {!!ledgerWarning && ( - - {ledgerWarning} - - )} - {(!!error || !!ledgerError) && ( - - {error || ledgerError} - - )} -
- - - {ledgerLocked - ? ( - - ) - : ( - - ) - } - - - ); -} - -export default styled(ImportLedger)` - .refreshIcon { - margin-right: 0.3rem; - } - - .ethereum-toggle { - margin: 1rem 0; - } -`; diff --git a/packages/extension-ui/src/Popup/Metadata/Request.tsx b/packages/extension-ui/src/Popup/Metadata/Request.tsx index 5ef41bc7..4785e4fe 100644 --- a/packages/extension-ui/src/Popup/Metadata/Request.tsx +++ b/packages/extension-ui/src/Popup/Metadata/Request.tsx @@ -70,7 +70,7 @@ function Request ({ className, metaId, request, url }: Props): React.ReactElemen
- {t('This approval will add the metadata to your extension instance, allowing future requests to be decoded using this metadata. It will also allow the use of Ledger\'s Generic Polkadot App.')} + {t('This approval will add the metadata to your extension instance, allowing future requests to be decoded using this metadata.')} - ) - : ( - - ) - } -
- ); -} - -export default styled(LedgerSign) ` - flex-direction: column; - padding: 6px 24px; - - .danger { - margin-bottom: .5rem; - } -`; diff --git a/packages/extension-ui/src/Popup/Signing/Request/index.tsx b/packages/extension-ui/src/Popup/Signing/Request/index.tsx index 7ba56c3c..fd7490f6 100644 --- a/packages/extension-ui/src/Popup/Signing/Request/index.tsx +++ b/packages/extension-ui/src/Popup/Signing/Request/index.tsx @@ -15,7 +15,6 @@ import { useMetadata, useTranslation } from '../../../hooks/index.js'; import { approveSignSignature } from '../../../messaging.js'; import Bytes from '../Bytes.js'; import Extrinsic from '../Extrinsic.js'; -import LedgerSign from '../LedgerSign.js'; import Qr from '../Qr.js'; import SignArea from './SignArea.js'; @@ -39,7 +38,7 @@ export const CMD_SIGN_MESSAGE = 3; // keep it global, we can and will re-use this across requests const registry = new TypeRegistry(); -export default function Request ({ account: { accountIndex, addressOffset, genesisHash: accountGenesisHash, isExternal, isHardware, type }, buttonText, isFirst, request, signId, url }: Props): React.ReactElement | null { +export default function Request ({ account: { genesisHash: accountGenesisHash, isExternal, isHardware }, buttonText, isFirst, request, signId, url }: Props): React.ReactElement | null { const onAction = useContext(ActionContext); const [{ hexBytes, payload }, setData] = useState({ hexBytes: null, payload: null }); const [error, setError] = useState(null); @@ -55,7 +54,6 @@ export default function Request ({ account: { accountIndex, addressOffset, genes useEffect((): void => { // When the chain and request are ready, configure the chain's registry. - // This will be picked up by LedgerSign. if (chain && isExtrinsicRequest(request)) { chain.registry.setSignedExtensions(request.payload.signedExtensions, chain.definition.userExtensions); } @@ -129,19 +127,6 @@ export default function Request ({ account: { accountIndex, addressOffset, genes /> ) } - {isHardware && ( - - )} {wrapWithErrorBoundary(, 'forget-address')} {wrapWithErrorBoundary(, 'export-address')} {wrapWithErrorBoundary(, 'export-all-address')} - {wrapWithErrorBoundary(, 'import-ledger')} {wrapWithErrorBoundary(, 'import-qr')} {wrapWithErrorBoundary(, 'import-seed')} {wrapWithErrorBoundary(, 'restore-json')} diff --git a/packages/extension-ui/src/hooks/index.js b/packages/extension-ui/src/hooks/index.js index efb0ce37..5e1e98cb 100644 --- a/packages/extension-ui/src/hooks/index.js +++ b/packages/extension-ui/src/hooks/index.js @@ -4,7 +4,6 @@ export { default as useGenesisHashOptions } from './useGenesisHashOptions.js'; export { default as useIsMounted } from './useIsMounted.js'; export { default as useIsPopup } from './useIsPopup.js'; -export { default as useLedger } from './useLedger.js'; export { default as useMetadata } from './useMetadata.js'; export { default as useOutsideClick } from './useOutsideClick.js'; export { default as useToast } from './useToast.js'; diff --git a/packages/extension-ui/src/hooks/useLedger.ts b/packages/extension-ui/src/hooks/useLedger.ts deleted file mode 100644 index b90f0a0f..00000000 --- a/packages/extension-ui/src/hooks/useLedger.ts +++ /dev/null @@ -1,287 +0,0 @@ -// Copyright 2019-2026 @polkadot/extension-ui authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -// This is to ensure the legacy `class Ledger` doesn't throw linting errors. -// -/* eslint-disable deprecation/deprecation */ - -import type { Network } from '@polkadot/networks/types'; -import type { HexString } from '@polkadot/util/types'; -import type { KeypairType } from '@polkadot/util-crypto/types'; - -import { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; - -import { Ledger, LedgerGeneric } from '@polkadot/hw-ledger'; -import { knownLedger } from '@polkadot/networks/defaults'; -import { settings } from '@polkadot/ui-settings'; -import { assert } from '@polkadot/util'; - -import { SettingsContext } from '../components/contexts.js'; -import chains from '../util/chains.js'; -import ledgerChains from '../util/legerChains.js'; -import useTranslation from './useTranslation.js'; - -interface StateBase { - isLedgerCapable: boolean; - isLedgerEnabled: boolean; -} - -interface State extends StateBase { - address: string | null; - error: string | null; - isLoading: boolean; - isLocked: boolean; - ledger: LedgerGeneric | Ledger | null; - refresh: () => void; - type: KeypairType | null; - warning: string | null; -} - -function getNetwork (genesisHash: string): Network | undefined { - return ledgerChains.find(({ genesisHash: [hash] }) => hash === genesisHash); -} - -function getTransportType (): 'hid' | 'webusb' { - // prefer WebHID over WebUSB. - return ('hid' in navigator) ? 'hid' : 'webusb'; -} - -function getState (): StateBase { - const w = window as unknown as { USB?: unknown; hid?: unknown }; - const isLedgerCapable = !!(w.hid || w.USB); - - return { - isLedgerCapable, - isLedgerEnabled: isLedgerCapable && settings.ledgerConn !== 'none' - }; -} - -function retrieveLedger (genesis: string | null, ledgerApp: string): LedgerGeneric | Ledger { - const { isLedgerCapable } = getState(); - - assert(isLedgerCapable, 'Incompatible browser, only Chrome is supported'); - - const transport = getTransportType(); - - if (ledgerApp === 'generic') { - // Generic app always uses Polkadot's slip44, regardless of chain genesis. - return new LedgerGeneric(transport, 'polkadot', knownLedger['polkadot']); - } - - // Shouldn't happen but guard to satisfy the compiler - assert(genesis, 'Genesis hash is required to connect to the Ledger in non-generic mode'); - - const def = getNetwork(genesis); - - assert(def, 'There is no known Ledger app available for this chain'); - - assert(def.slip44, 'Slip44 is not available for this network, please report an issue to update this chains slip44'); - - if (ledgerApp === 'migration') { - return new LedgerGeneric(transport, def.network, knownLedger[def.network]); - } - - if (ledgerApp === 'chainSpecific') { - return new Ledger(transport, def.network); - } - - // This will never get touched since it will always hit the above two. This satisfies the compiler. - return new LedgerGeneric(transport, 'polkadot', knownLedger['polkadot']); -} - -export default function useLedger (genesis?: string | null, accountIndex = 0, addressOffset = 0, isEthereum = false): State { - const [isLoading, setIsLoading] = useState(false); - const [isLocked, setIsLocked] = useState(false); - const [refreshCount, setRefreshCount] = useState(0); - const [warning, setWarning] = useState(null); - const [error, setError] = useState(null); - const [address, setAddress] = useState(null); - const [type, setType] = useState(null); - const { t } = useTranslation(); - const { ledgerApp } = useContext(SettingsContext); - const tRef = useRef(t); - // Holds the ledger from the previous effect run so we can close its - // transport when the network changes and a new instance is created. - const prevLedgerRef = useRef(null); - - // Keep a stable reference so effects and callbacks don't depend on - // i18n function identity changes. - tRef.current = t; - - const handleGetAddressError = useCallback((e: Error, genesis: string, ledgerApp: string) => { - setIsLoading(false); - const { network } = getNetwork(genesis) || { network: ledgerApp === 'generic' ? 'Polkadot' : 'unknown network' }; - - const warningMessage = e.message.includes('Code: 26628') - ? tRef.current('Is your ledger locked?') - : null; - - const errorMessage = e.message.includes('App does not seem to be open') - ? tRef.current('App "{{network}}" does not seem to be open', { replace: { network } }) - : e.message; - - setIsLocked(true); - setWarning(warningMessage); - setError(tRef.current( - 'Ledger error: {{errorMessage}}', - { replace: { errorMessage } } - )); - console.error(e); - setAddress(null); - setType(null); - }, []); - - const { ledger, ledgerInitError } = useMemo(() => { - // undefined means no ledger connection attempt. - // null means connect using the generic app without a specific chain genesis. - // Prevents hook instances that only check isLedgerCapable or isLedgerEnabled - // from attempting a connection when ledgerApp === 'generic'. - if (genesis === undefined) { - return { ledger: null, ledgerInitError: null }; - } - - // Generic app connects without a specific chain genesis (always derives from polkadot). - const canConnect = ledgerApp === 'generic' || refreshCount > 0 || !!genesis; - - if (!canConnect || (ledgerApp !== 'generic' && !genesis)) { - return { ledger: null, ledgerInitError: null }; - } - - try { - return { ledger: retrieveLedger(genesis ?? null, ledgerApp), ledgerInitError: null }; - } catch (error) { - return { ledger: null, ledgerInitError: (error as Error).message }; - } - }, [genesis, ledgerApp, refreshCount]); - - useEffect(() => { - setError(ledgerInitError); - }, [ledgerInitError]); - - useEffect(() => { - let isStale = false; - - if (!ledger || (ledgerApp !== 'generic' && !genesis)) { - if (prevLedgerRef.current) { - prevLedgerRef.current.disconnect().catch(console.error); - prevLedgerRef.current = null; - } - - setIsLoading(false); - setIsLocked(false); - setWarning(null); - setAddress(null); - setType(null); - - return () => { - isStale = true; - }; - } - - const runIfCurrent = (fn: () => void): void => { - if (!isStale) { - fn(); - } - }; - - const onAddressError = (e: Error): void => { - if (!isStale) { - handleGetAddressError(e, genesis ?? '', ledgerApp); - } - }; - - setIsLoading(true); - setError(null); - setWarning(null); - - const prevLedger = prevLedgerRef.current; - - prevLedgerRef.current = ledger; - - const fetchLedgerAddress = () => { - if (isStale) { - return; - } - - const chosenNetwork = chains.find(({ genesisHash }) => genesisHash === genesis as HexString); - // Use the chain's SS58 prefix when known; fall back to 42 (substrate default). - const ss58Prefix = chosenNetwork?.ss58Format ?? 42; - - if (ledgerApp === 'migration') { - // Migration app is only expected on known, mapped chains. - assert(chosenNetwork, tRef.current('This network is not available, please report an issue to update the known chains')); - } - - if (ledgerApp === 'generic' || ledgerApp === 'migration') { - if (isEthereum) { - (ledger as LedgerGeneric).getAddressEcdsa(false, accountIndex, addressOffset) - .then((res) => { - runIfCurrent(() => { - setIsLoading(false); - setIsLocked(false); - setAddress(`0x${res.address}`); - setType('ethereum'); - }); - }).catch(onAddressError); - } else { - (ledger as LedgerGeneric).getAddress(ss58Prefix, false, accountIndex, addressOffset) - .then((res) => { - runIfCurrent(() => { - setIsLoading(false); - setIsLocked(false); - setAddress(res.address); - setType('ed25519'); - }); - }).catch(onAddressError); - } - } else if (ledgerApp === 'chainSpecific') { - (ledger as Ledger).getAddress(false, accountIndex, addressOffset) - .then((res) => { - runIfCurrent(() => { - setIsLoading(false); - setIsLocked(false); - setAddress(res.address); - setType('ed25519'); - }); - }).catch(onAddressError); - } - }; - - // Disconnect the previous instance before opening the new one (network or ledger app change). - if (prevLedger && prevLedger !== ledger) { - prevLedger.disconnect().catch(console.error).finally(fetchLedgerAddress); - } else { - fetchLedgerAddress(); - } - - return () => { - isStale = true; - }; - }, [accountIndex, addressOffset, genesis, handleGetAddressError, ledger, ledgerApp, isEthereum]); - - const ledgerRef = useRef(ledger); - - // Keep in sync so the unmount cleanup always closes the latest instance. - ledgerRef.current = ledger; - - // On unmount, release the transport so the next session can open it. - useEffect(() => { - return () => { - ledgerRef.current?.disconnect().catch(console.error); - }; - }, []); - - const refresh = useCallback(() => { - if (ledger) { - // Prevent the address-fetch effect from disconnecting this instance again. - prevLedgerRef.current = null; - ledger.disconnect() - .catch(console.error) - .finally(() => setRefreshCount((c) => c + 1)); - } else { - setRefreshCount((c) => c + 1); - } - }, [ledger]); - - return ({ ...getState(), address, error, isLoading, isLocked, ledger, refresh, type, warning }); -} diff --git a/packages/extension-ui/src/messaging.ts b/packages/extension-ui/src/messaging.ts index 238e24ba..1d6296f6 100644 --- a/packages/extension-ui/src/messaging.ts +++ b/packages/extension-ui/src/messaging.ts @@ -143,10 +143,6 @@ export async function createAccountExternal (name: string, address: string, gene return sendMessage('pri(accounts.create.external)', { address, genesisHash, name }); } -export async function createAccountHardware (address: string, hardwareType: string, accountIndex: number, addressOffset: number, name: string, genesisHash: HexString | null, type: KeypairType): Promise { - return sendMessage('pri(accounts.create.hardware)', { accountIndex, address, addressOffset, genesisHash, hardwareType, name, type }); -} - export async function createAccountSuri (name: string, password: string, suri: string, type?: KeypairType, genesisHash?: HexString | null): Promise { return sendMessage('pri(accounts.create.suri)', { genesisHash, name, password, suri, type }); } diff --git a/packages/extension-ui/src/partials/MenuAdd.tsx b/packages/extension-ui/src/partials/MenuAdd.tsx index a00c5472..2345870c 100644 --- a/packages/extension-ui/src/partials/MenuAdd.tsx +++ b/packages/extension-ui/src/partials/MenuAdd.tsx @@ -1,13 +1,12 @@ // Copyright 2019-2026 @polkadot/extension-ui authors & contributors // SPDX-License-Identifier: Apache-2.0 -import { faUsb } from '@fortawesome/free-brands-svg-icons'; import { faCodeBranch, faFileExport, faFileUpload, faKey, faPlusCircle, faQrcode } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import React, { useCallback, useContext } from 'react'; import { AccountContext, Link, MediaContext, Menu, MenuDivider, MenuItem } from '../components/index.js'; -import { useIsPopup, useLedger, useTranslation } from '../hooks/index.js'; +import { useIsPopup, useTranslation } from '../hooks/index.js'; import { windowOpen } from '../messaging.js'; import { styled } from '../styled.js'; @@ -17,13 +16,11 @@ interface Props { } const jsonPath = '/account/restore-json'; -const ledgerPath = '/account/import-ledger'; function MenuAdd ({ className, reference }: Props): React.ReactElement { const { t } = useTranslation(); const { master } = useContext(AccountContext); const mediaAllowed = useContext(MediaContext); - const { isLedgerCapable, isLedgerEnabled } = useLedger(); const isPopup = useIsPopup(); const _openJson = useCallback( @@ -32,12 +29,6 @@ function MenuAdd ({ className, reference }: Props): React.ReactElement { }, [] ); - const _onOpenLedgerConnect = useCallback( - (): void => { - windowOpen(ledgerPath).catch(console.error); - }, [] - ); - return ( { {t('Attach external QR-signer account')} - - {isLedgerEnabled - ? ( - - - { t('Attach ledger account')} - - ) - : ( - - - { t('Connect Ledger device')} - - ) - } - ); } diff --git a/packages/extension-ui/src/partials/MenuSettings.tsx b/packages/extension-ui/src/partials/MenuSettings.tsx index f7379442..944a53a1 100644 --- a/packages/extension-ui/src/partials/MenuSettings.tsx +++ b/packages/extension-ui/src/partials/MenuSettings.tsx @@ -39,7 +39,6 @@ function MenuSettings ({ className, reference }: Props): React.ReactElement getLanguageOptions(), []); const onAction = useContext(ActionContext); - const _ledgerAppOptions = settings.availableLedgerApp; useEffect(() => { settings.set({ camera: camera ? 'on' : 'off' }); @@ -83,11 +82,6 @@ function MenuSettings ({ className, reference }: Props): React.ReactElement { - settings.set({ ledgerApp: value }); - }, [] - ); const _goToAuthList = useCallback( () => { @@ -123,18 +117,6 @@ function MenuSettings ({ className, reference }: Props): React.ReactElement - - - ` font-size: 15px; margin-bottom: 0; - &.ledger { - margin-top: 0.2rem; - } label { color: var(--textColor); diff --git a/packages/extension-ui/src/util/legerChains.ts b/packages/extension-ui/src/util/legerChains.ts deleted file mode 100644 index 21535ad1..00000000 --- a/packages/extension-ui/src/util/legerChains.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Copyright 2019-2026 @polkadot/extension-ui authors & contributors -// SPDX-License-Identifier: Apache-2.0 - -import { selectableNetworks } from '@polkadot/networks'; - -export default selectableNetworks.filter((network) => network.hasLedgerSupport); diff --git a/yarn.lock b/yarn.lock index a771fcd4..5cee0432 100644 --- a/yarn.lock +++ b/yarn.lock @@ -408,108 +408,6 @@ __metadata: languageName: node linkType: hard -"@ledgerhq/devices@npm:8.4.7, @ledgerhq/devices@npm:^8.4.4": - version: 8.4.7 - resolution: "@ledgerhq/devices@npm:8.4.7" - dependencies: - "@ledgerhq/errors": "npm:^6.22.0" - "@ledgerhq/logs": "npm:^6.13.0" - rxjs: "npm:^7.8.1" - semver: "npm:^7.3.5" - checksum: 10/1d49aa692831915f1a540cba2d7faba3a08e5a2d1db831e3849c7791526d6ebb85fab679585f6940d5a923abf91f2113d675445172e37b38d742c3f18952e0fc - languageName: node - linkType: hard - -"@ledgerhq/errors@npm:^6.19.1, @ledgerhq/errors@npm:^6.22.0": - version: 6.22.0 - resolution: "@ledgerhq/errors@npm:6.22.0" - checksum: 10/6bea0c5fbb07c4f20fbc5083856646708c195c6d138dcbeed1f08f88c97536fd5059959a724332c45f17b8944aa8d8e68d850f43b33bf5b2f30d901c593e2930 - languageName: node - linkType: hard - -"@ledgerhq/hw-transport-node-hid-noevents@npm:^6.30.8": - version: 6.30.8 - resolution: "@ledgerhq/hw-transport-node-hid-noevents@npm:6.30.8" - dependencies: - "@ledgerhq/devices": "npm:8.4.7" - "@ledgerhq/errors": "npm:^6.22.0" - "@ledgerhq/hw-transport": "npm:^6.31.7" - "@ledgerhq/logs": "npm:^6.13.0" - node-hid: "npm:2.1.2" - checksum: 10/b6e5795636431d06befd64cded66f300b8c81bfa8d590d56f728662e77074cb26898903be6371c1f3a720473173f6c5d223778b2ac8ad84e7b450ed64168f901 - languageName: node - linkType: hard - -"@ledgerhq/hw-transport-node-hid-singleton@npm:^6.31.5": - version: 6.31.8 - resolution: "@ledgerhq/hw-transport-node-hid-singleton@npm:6.31.8" - dependencies: - "@ledgerhq/devices": "npm:8.4.7" - "@ledgerhq/errors": "npm:^6.22.0" - "@ledgerhq/hw-transport": "npm:^6.31.7" - "@ledgerhq/hw-transport-node-hid-noevents": "npm:^6.30.8" - "@ledgerhq/logs": "npm:^6.13.0" - node-hid: "npm:2.1.2" - usb: "npm:2.9.0" - checksum: 10/d79272bcb79d863f9b7934a4175e4564faea71257ec419675942e964f95ad9ae159632594f63f86e55c68572c7377848de9f3f4ecf684134beddf182f1a462cb - languageName: node - linkType: hard - -"@ledgerhq/hw-transport-webhid@npm:^6.29.4": - version: 6.30.3 - resolution: "@ledgerhq/hw-transport-webhid@npm:6.30.3" - dependencies: - "@ledgerhq/devices": "npm:8.4.7" - "@ledgerhq/errors": "npm:^6.22.0" - "@ledgerhq/hw-transport": "npm:^6.31.7" - "@ledgerhq/logs": "npm:^6.13.0" - checksum: 10/4f9ea31952fd07e366fab0acd020cabdf2346e03aaa6971805aeec8820225ffac66a57aaf375137f599ba0e9fd42f7b3febd923dd3b420b70a421588054b2135 - languageName: node - linkType: hard - -"@ledgerhq/hw-transport-webusb@npm:^6.29.4": - version: 6.29.7 - resolution: "@ledgerhq/hw-transport-webusb@npm:6.29.7" - dependencies: - "@ledgerhq/devices": "npm:8.4.7" - "@ledgerhq/errors": "npm:^6.22.0" - "@ledgerhq/hw-transport": "npm:^6.31.7" - "@ledgerhq/logs": "npm:^6.13.0" - checksum: 10/2beb65383939df07c0df18e2b8d97c41e1fffbba4af9bccf26639d3814c617f47293f5a16b268340b5e64fe1f45f4b5a65ecc4edba3c502984d2fa92bed25c2b - languageName: node - linkType: hard - -"@ledgerhq/hw-transport@npm:6.31.4": - version: 6.31.4 - resolution: "@ledgerhq/hw-transport@npm:6.31.4" - dependencies: - "@ledgerhq/devices": "npm:^8.4.4" - "@ledgerhq/errors": "npm:^6.19.1" - "@ledgerhq/logs": "npm:^6.12.0" - events: "npm:^3.3.0" - checksum: 10/cf101e5b818e95e59031241d556dbec24658f54104910e414be493bc4b90b0aea50f5d4b3339a237dd0b12845bb2683c845f3a82f2ea9da4e077b68d1e1f7e48 - languageName: node - linkType: hard - -"@ledgerhq/hw-transport@npm:^6.31.4, @ledgerhq/hw-transport@npm:^6.31.7": - version: 6.31.7 - resolution: "@ledgerhq/hw-transport@npm:6.31.7" - dependencies: - "@ledgerhq/devices": "npm:8.4.7" - "@ledgerhq/errors": "npm:^6.22.0" - "@ledgerhq/logs": "npm:^6.13.0" - events: "npm:^3.3.0" - checksum: 10/a8c44980fb1d795f23fe62edc6a7b910efcb2dda6b626f6ac3a6b2efd4c855d6591e9cd6fa3d7d65c89eea2418ee4b960878cc6be0d73e7e2a958d3af378f44a - languageName: node - linkType: hard - -"@ledgerhq/logs@npm:^6.12.0, @ledgerhq/logs@npm:^6.13.0": - version: 6.13.0 - resolution: "@ledgerhq/logs@npm:6.13.0" - checksum: 10/3ac984bdc533505359cd1d8bc74175547fcfa51fef6294a9fd832e8ea88d462a385be5cfe68ccfa1b77cd68b840243e6f79c2be66fe28f123ae57c58625edf5f - languageName: node - linkType: hard - "@leichtgewicht/ip-codec@npm:^2.0.1": version: 2.0.5 resolution: "@leichtgewicht/ip-codec@npm:2.0.5" @@ -1184,7 +1082,6 @@ __metadata: "@polkadot/extension-dapp": "npm:0.64.0" "@polkadot/extension-inject": "npm:0.64.0" "@polkadot/extension-mocks": "npm:0.64.0" - "@polkadot/hw-ledger": "npm:^14.0.3" "@polkadot/keyring": "npm:^14.0.3" "@polkadot/networks": "npm:^14.0.3" "@polkadot/react-identicon": "npm:^3.16.7" @@ -1253,35 +1150,6 @@ __metadata: languageName: unknown linkType: soft -"@polkadot/hw-ledger-transports@npm:14.0.3": - version: 14.0.3 - resolution: "@polkadot/hw-ledger-transports@npm:14.0.3" - dependencies: - "@ledgerhq/hw-transport": "npm:^6.31.4" - "@ledgerhq/hw-transport-node-hid-singleton": "npm:^6.31.5" - "@ledgerhq/hw-transport-webhid": "npm:^6.29.4" - "@ledgerhq/hw-transport-webusb": "npm:^6.29.4" - "@polkadot/util": "npm:14.0.3" - tslib: "npm:^2.8.0" - dependenciesMeta: - "@ledgerhq/hw-transport-node-hid-singleton": - optional: true - checksum: 10/5cf48a41079e06ea4c46df4c4aaf2efcca786b19f9eecb0c7c0ba505a1f5a98f730518cff41e3b0fa27f09d6dc74329e2f2b982a2dd8f1c7e59db9d65b90eabe - languageName: node - linkType: hard - -"@polkadot/hw-ledger@npm:^14.0.3": - version: 14.0.3 - resolution: "@polkadot/hw-ledger@npm:14.0.3" - dependencies: - "@polkadot/hw-ledger-transports": "npm:14.0.3" - "@polkadot/util": "npm:14.0.3" - "@zondax/ledger-substrate": "npm:1.1.1" - tslib: "npm:^2.8.0" - checksum: 10/1f4746a3fd7f311211c451ba26ff1cd11bcfc729c27bc9516e619e5df2d57a9e79e94b163d2e00448864680c7afa0d20b933932134bafa709af091db1e6d9b10 - languageName: node - linkType: hard - "@polkadot/keyring@https://git.lair.cafe/api/packages/quantus/npm/%40polkadot%2Fkeyring/-/14.0.3-quantus.1/keyring-14.0.3-quantus.1.tgz": version: 14.0.3-quantus.1 resolution: "@polkadot/keyring@https://git.lair.cafe/api/packages/quantus/npm/%40polkadot%2Fkeyring/-/14.0.3-quantus.1/keyring-14.0.3-quantus.1.tgz" @@ -2649,13 +2517,6 @@ __metadata: languageName: node linkType: hard -"@types/w3c-web-usb@npm:^1.0.6": - version: 1.0.10 - resolution: "@types/w3c-web-usb@npm:1.0.10" - checksum: 10/6ac6786a0788f0846a48b103ab06ca5fde5eb95674217b522420a2f6157bee3e181a961c1b7011940f497c55f4f5cc46129657d881fdd8112b48764089679ad6 - languageName: node - linkType: hard - "@types/ws@npm:8.5.3": version: 8.5.3 resolution: "@types/ws@npm:8.5.3" @@ -3267,26 +3128,6 @@ __metadata: languageName: node linkType: hard -"@zondax/ledger-js@npm:^1.2.0": - version: 1.2.0 - resolution: "@zondax/ledger-js@npm:1.2.0" - dependencies: - "@ledgerhq/hw-transport": "npm:6.31.4" - checksum: 10/5852b340efd421f96d4e52d0a93d4e8464604c070939dd42fade5a495010a08d730b03e1b7ab3ff0f26f13075d8a0a5226a748a41986f2ed087fca4471f24e4e - languageName: node - linkType: hard - -"@zondax/ledger-substrate@npm:1.1.1": - version: 1.1.1 - resolution: "@zondax/ledger-substrate@npm:1.1.1" - dependencies: - "@ledgerhq/hw-transport": "npm:6.31.4" - "@zondax/ledger-js": "npm:^1.2.0" - axios: "npm:^1.8.4" - checksum: 10/039ffef55b31870f82c6b0f20b518089ad9ce0295d695f880640cb586256adacd4a326c10157ccaf82e897abde7358f9e4e02c069dac672ec90881e21d250722 - languageName: node - linkType: hard - "@zxcvbn-ts/core@npm:^3.0.4": version: 3.0.4 resolution: "@zxcvbn-ts/core@npm:3.0.4" @@ -3909,17 +3750,6 @@ __metadata: languageName: node linkType: hard -"axios@npm:^1.8.4": - version: 1.10.0 - resolution: "axios@npm:1.10.0" - dependencies: - follow-redirects: "npm:^1.15.6" - form-data: "npm:^4.0.0" - proxy-from-env: "npm:^1.1.0" - checksum: 10/d43c80316a45611fd395743e15d16ea69a95f2b7f7095f2bb12cb78f9ca0a905194a02e52a3bf4e0db9f85fd1186d6c690410644c10ecd8bb0a468e57c2040e4 - languageName: node - linkType: hard - "b4a@npm:^1.6.4": version: 1.6.7 resolution: "b4a@npm:1.6.7" @@ -4602,16 +4432,7 @@ __metadata: languageName: node linkType: hard -"bindings@npm:^1.5.0": - version: 1.5.0 - resolution: "bindings@npm:1.5.0" - dependencies: - file-uri-to-path: "npm:1.0.0" - checksum: 10/593d5ae975ffba15fbbb4788fe5abd1e125afbab849ab967ab43691d27d6483751805d98cb92f7ac24a2439a8a8678cd0131c535d5d63de84e383b0ce2786133 - languageName: node - linkType: hard - -"bl@npm:^4.0.3, bl@npm:^4.1.0": +"bl@npm:^4.1.0": version: 4.1.0 resolution: "bl@npm:4.1.0" dependencies: @@ -5131,13 +4952,6 @@ __metadata: languageName: node linkType: hard -"chownr@npm:^1.1.1": - version: 1.1.4 - resolution: "chownr@npm:1.1.4" - checksum: 10/115648f8eb38bac5e41c3857f3e663f9c39ed6480d1349977c4d96c95a47266fcacc5a5aabf3cb6c481e22d72f41992827db47301851766c4fd77ac21a4f081d - languageName: node - linkType: hard - "chownr@npm:^3.0.0": version: 3.0.0 resolution: "chownr@npm:3.0.0" @@ -5924,13 +5738,6 @@ __metadata: languageName: node linkType: hard -"detect-libc@npm:^2.0.0": - version: 2.0.4 - resolution: "detect-libc@npm:2.0.4" - checksum: 10/136e995f8c5ffbc515955b0175d441b967defd3d5f2268e89fa695e9c7170d8bed17993e31a34b04f0fad33d844a3a598e0fd519a8e9be3cad5f67662d96fee0 - languageName: node - linkType: hard - "detect-node@npm:^2.0.4": version: 2.1.0 resolution: "detect-node@npm:2.1.0" @@ -7192,7 +6999,7 @@ __metadata: languageName: node linkType: hard -"events@npm:^3.2.0, events@npm:^3.3.0": +"events@npm:^3.2.0": version: 3.3.0 resolution: "events@npm:3.3.0" checksum: 10/a3d47e285e28d324d7180f1e493961a2bbb4cad6412090e4dec114f4db1f5b560c7696ee8e758f55e23913ede856e3689cd3aa9ae13c56b5d8314cd3b3ddd1be @@ -7227,13 +7034,6 @@ __metadata: languageName: node linkType: hard -"expand-template@npm:^2.0.3": - version: 2.0.3 - resolution: "expand-template@npm:2.0.3" - checksum: 10/588c19847216421ed92befb521767b7018dc88f88b0576df98cb242f20961425e96a92cbece525ef28cc5becceae5d544ae0f5b9b5e2aa05acb13716ca5b3099 - languageName: node - linkType: hard - "exponential-backoff@npm:^3.1.1": version: 3.1.2 resolution: "exponential-backoff@npm:3.1.2" @@ -7454,13 +7254,6 @@ __metadata: languageName: node linkType: hard -"file-uri-to-path@npm:1.0.0": - version: 1.0.0 - resolution: "file-uri-to-path@npm:1.0.0" - checksum: 10/b648580bdd893a008c92c7ecc96c3ee57a5e7b6c4c18a9a09b44fb5d36d79146f8e442578bc0e173dc027adf3987e254ba1dfd6e3ec998b7c282873010502144 - languageName: node - linkType: hard - "filename-reserved-regex@npm:^2.0.0": version: 2.0.0 resolution: "filename-reserved-regex@npm:2.0.0" @@ -7591,7 +7384,7 @@ __metadata: languageName: node linkType: hard -"follow-redirects@npm:^1.0.0, follow-redirects@npm:^1.15.6": +"follow-redirects@npm:^1.0.0": version: 1.15.9 resolution: "follow-redirects@npm:1.15.9" peerDependenciesMeta: @@ -7656,13 +7449,6 @@ __metadata: languageName: node linkType: hard -"fs-constants@npm:^1.0.0": - version: 1.0.0 - resolution: "fs-constants@npm:1.0.0" - checksum: 10/18f5b718371816155849475ac36c7d0b24d39a11d91348cfcb308b4494824413e03572c403c86d3a260e049465518c4f0d5bd00f0371cdfcad6d4f30a85b350d - languageName: node - linkType: hard - "fs-extra@npm:^11.1.1": version: 11.3.0 resolution: "fs-extra@npm:11.3.0" @@ -7942,13 +7728,6 @@ __metadata: languageName: node linkType: hard -"github-from-package@npm:0.0.0": - version: 0.0.0 - resolution: "github-from-package@npm:0.0.0" - checksum: 10/2a091ba07fbce22205642543b4ea8aaf068397e1433c00ae0f9de36a3607baf5bcc14da97fbb798cfca6393b3c402031fca06d8b491a44206d6efef391c58537 - languageName: node - linkType: hard - "github-url-to-object@npm:^4.0.4": version: 4.0.6 resolution: "github-url-to-object@npm:4.0.6" @@ -10108,7 +9887,7 @@ __metadata: languageName: node linkType: hard -"minimist@npm:^1.2.0, minimist@npm:^1.2.3, minimist@npm:^1.2.5, minimist@npm:^1.2.6": +"minimist@npm:^1.2.0, minimist@npm:^1.2.5, minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" checksum: 10/908491b6cc15a6c440ba5b22780a0ba89b9810e1aea684e253e43c4e3b8d56ec1dcdd7ea96dde119c29df59c936cde16062159eae4225c691e19c70b432b6e6f @@ -10191,13 +9970,6 @@ __metadata: languageName: node linkType: hard -"mkdirp-classic@npm:^0.5.2, mkdirp-classic@npm:^0.5.3": - version: 0.5.3 - resolution: "mkdirp-classic@npm:0.5.3" - checksum: 10/3f4e088208270bbcc148d53b73e9a5bd9eef05ad2cbf3b3d0ff8795278d50dd1d11a8ef1875ff5aea3fa888931f95bfcb2ad5b7c1061cfefd6284d199e6776ac - languageName: node - linkType: hard - "mkdirp@npm:^0.5.1": version: 0.5.6 resolution: "mkdirp@npm:0.5.6" @@ -10313,13 +10085,6 @@ __metadata: languageName: node linkType: hard -"napi-build-utils@npm:^2.0.0": - version: 2.0.0 - resolution: "napi-build-utils@npm:2.0.0" - checksum: 10/69adcdb828481737f1ec64440286013f6479d5b264e24d5439ba795f65293d0bb6d962035de07c65fae525ed7d2fcd0baab6891d8e3734ea792fec43918acf83 - languageName: node - linkType: hard - "napi-postinstall@npm:^0.3.0": version: 0.3.0 resolution: "napi-postinstall@npm:0.3.0" @@ -10422,33 +10187,6 @@ __metadata: languageName: node linkType: hard -"node-abi@npm:^3.3.0": - version: 3.75.0 - resolution: "node-abi@npm:3.75.0" - dependencies: - semver: "npm:^7.3.5" - checksum: 10/dd87627fa4f447bda9c69dc1ec0da82e3b466790844b5bd7f7787db093dfea21dcc405588e13b5207c266472c1fda9b95060da8d70644aeb5fc31ec81dc2007c - languageName: node - linkType: hard - -"node-addon-api@npm:^3.0.2": - version: 3.2.1 - resolution: "node-addon-api@npm:3.2.1" - dependencies: - node-gyp: "npm:latest" - checksum: 10/681b52dfa3e15b0a8e5cf283cc0d8cd5fd2a57c559ae670fcfd20544cbb32f75de7648674110defcd17ab2c76ebef630aa7d2d2f930bc7a8cc439b20fe233518 - languageName: node - linkType: hard - -"node-addon-api@npm:^6.0.0": - version: 6.1.0 - resolution: "node-addon-api@npm:6.1.0" - dependencies: - node-gyp: "npm:latest" - checksum: 10/8eea1d4d965930a177a0508695beb0d89b4c1d80bf330646a035357a1e8fc31e0d09686e2374996e96e757b947a7ece319f98ede3146683f162597c0bcb4df90 - languageName: node - linkType: hard - "node-domexception@npm:^1.0.0": version: 1.0.0 resolution: "node-domexception@npm:1.0.0" @@ -10488,17 +10226,6 @@ __metadata: languageName: node linkType: hard -"node-gyp-build@npm:^4.5.0": - version: 4.8.4 - resolution: "node-gyp-build@npm:4.8.4" - bin: - node-gyp-build: bin.js - node-gyp-build-optional: optional.js - node-gyp-build-test: build-test.js - checksum: 10/6a7d62289d1afc419fc8fc9bd00aa4e554369e50ca0acbc215cb91446148b75ff7e2a3b53c2c5b2c09a39d416d69f3d3237937860373104b5fe429bf30ad9ac5 - languageName: node - linkType: hard - "node-gyp@npm:latest": version: 11.2.0 resolution: "node-gyp@npm:11.2.0" @@ -10519,20 +10246,6 @@ __metadata: languageName: node linkType: hard -"node-hid@npm:2.1.2": - version: 2.1.2 - resolution: "node-hid@npm:2.1.2" - dependencies: - bindings: "npm:^1.5.0" - node-addon-api: "npm:^3.0.2" - node-gyp: "npm:latest" - prebuild-install: "npm:^7.1.1" - bin: - hid-showdevices: src/show-devices.js - checksum: 10/7b424d9f049221b439cfa3a092f415b608bcd316b819ff1fb0bf5234d766348d9fdaeaafa5ccece514c045825a936cb5617080168066d16b3aaeb0e9808e38f9 - languageName: node - linkType: hard - "node-releases@npm:^2.0.19": version: 2.0.19 resolution: "node-releases@npm:2.0.19" @@ -11223,28 +10936,6 @@ __metadata: languageName: node linkType: hard -"prebuild-install@npm:^7.1.1": - version: 7.1.3 - resolution: "prebuild-install@npm:7.1.3" - dependencies: - detect-libc: "npm:^2.0.0" - expand-template: "npm:^2.0.3" - github-from-package: "npm:0.0.0" - minimist: "npm:^1.2.3" - mkdirp-classic: "npm:^0.5.3" - napi-build-utils: "npm:^2.0.0" - node-abi: "npm:^3.3.0" - pump: "npm:^3.0.0" - rc: "npm:^1.2.7" - simple-get: "npm:^4.0.0" - tar-fs: "npm:^2.0.0" - tunnel-agent: "npm:^0.6.0" - bin: - prebuild-install: bin.js - checksum: 10/1b7e4c00d2750b532a4fc2a83ffb0c5fefa1b6f2ad071896ead15eeadc3255f5babd816949991af083cf7429e375ae8c7d1c51f73658559da36f948a020a3a11 - languageName: node - linkType: hard - "precinct@npm:^8.1.0": version: 8.3.1 resolution: "precinct@npm:8.3.1" @@ -11403,13 +11094,6 @@ __metadata: languageName: node linkType: hard -"proxy-from-env@npm:^1.1.0": - version: 1.1.0 - resolution: "proxy-from-env@npm:1.1.0" - checksum: 10/f0bb4a87cfd18f77bc2fba23ae49c3b378fb35143af16cc478171c623eebe181678f09439707ad80081d340d1593cd54a33a0113f3ccb3f4bc9451488780ee23 - languageName: node - linkType: hard - "psl@npm:^1.1.33": version: 1.15.0 resolution: "psl@npm:1.15.0" @@ -13361,31 +13045,6 @@ __metadata: languageName: node linkType: hard -"tar-fs@npm:^2.0.0": - version: 2.1.3 - resolution: "tar-fs@npm:2.1.3" - dependencies: - chownr: "npm:^1.1.1" - mkdirp-classic: "npm:^0.5.2" - pump: "npm:^3.0.0" - tar-stream: "npm:^2.1.4" - checksum: 10/37fdfd3aa73f4f49c0821ef75f67647ecafd5370d2e311d9ace6ff3825ff4355014055c3d43407c6a655adf6c5bfb0cbcf93412161dad5af7110eb7d7a0c2eae - languageName: node - linkType: hard - -"tar-stream@npm:^2.1.4": - version: 2.2.0 - resolution: "tar-stream@npm:2.2.0" - dependencies: - bl: "npm:^4.0.3" - end-of-stream: "npm:^1.4.1" - fs-constants: "npm:^1.0.0" - inherits: "npm:^2.0.3" - readable-stream: "npm:^3.1.1" - checksum: 10/1a52a51d240c118cbcd30f7368ea5e5baef1eac3e6b793fb1a41e6cd7319296c79c0264ccc5859f5294aa80f8f00b9239d519e627b9aade80038de6f966fec6a - languageName: node - linkType: hard - "tar@npm:^7.4.3": version: 7.4.3 resolution: "tar@npm:7.4.3" @@ -13729,15 +13388,6 @@ __metadata: languageName: node linkType: hard -"tunnel-agent@npm:^0.6.0": - version: 0.6.0 - resolution: "tunnel-agent@npm:0.6.0" - dependencies: - safe-buffer: "npm:^5.0.1" - checksum: 10/7f0d9ed5c22404072b2ae8edc45c071772affd2ed14a74f03b4e71b4dd1a14c3714d85aed64abcaaee5fec2efc79002ba81155c708f4df65821b444abb0cfade - languageName: node - linkType: hard - "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -14117,18 +13767,6 @@ __metadata: languageName: node linkType: hard -"usb@npm:2.9.0": - version: 2.9.0 - resolution: "usb@npm:2.9.0" - dependencies: - "@types/w3c-web-usb": "npm:^1.0.6" - node-addon-api: "npm:^6.0.0" - node-gyp: "npm:latest" - node-gyp-build: "npm:^4.5.0" - checksum: 10/ab68d4247a24a463328e293256aec5682c12163278ab474b7243a9dba6283a44bb74f9e0ca96f1d00197bb271f294549c3a4debdbd3452a02750a4a65ff29ee6 - languageName: node - linkType: hard - "util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2"