@onekeyfe/hwk-desktop-noble-ble 1.2.3-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-RNZYQRXV.mjs +39 -0
- package/dist/chunk-RNZYQRXV.mjs.map +1 -0
- package/dist/constants.d.mts +36 -0
- package/dist/constants.d.ts +36 -0
- package/dist/constants.js +59 -0
- package/dist/constants.js.map +1 -0
- package/dist/constants.mjs +15 -0
- package/dist/constants.mjs.map +1 -0
- package/dist/index.d.mts +357 -0
- package/dist/index.d.ts +357 -0
- package/dist/index.js +948 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +900 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +82 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/debugLog.ts","../src/NobleBleHandler.ts","../src/main.ts"],"sourcesContent":["export type BleDebugLogLevel = 'debug' | 'info' | 'warn' | 'error';\n\nexport type BleDebugLogEntry = {\n level: BleDebugLogLevel;\n scope: string;\n event: string;\n data?: Record<string, unknown>;\n};\n\nexport type BleDebugLogger = (entry: BleDebugLogEntry) => void;\n\n/**\n * Keys whose values never belong in a log. This handler only ever sees\n * transport-level data — device ids, names, counts — but a caller can pass an\n * arbitrary `data` bag, and a raw frame or a pairing secret reaching an\n * on-disk log is not something to leave to caller discipline.\n */\nconst REDACTED_KEYS: ReadonlySet<string> = new Set([\n 'credential',\n 'credentials',\n 'privateKey',\n 'publicKey',\n 'hostKey',\n 'pin',\n 'passphrase',\n 'hexData',\n 'payload',\n 'bytes',\n]);\n\n/** Replace sensitive values in place; everything else is forwarded verbatim. */\nexport function redactBleDebugLogData(\n data?: Record<string, unknown>\n): Record<string, unknown> | undefined {\n if (!data) return undefined;\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n out[key] = REDACTED_KEYS.has(key) ? '[redacted]' : value;\n }\n return out;\n}\n","import { type BleDebugLogLevel, type BleDebugLogger, redactBleDebugLogData } from './debugLog';\nimport {\n THIRD_PARTY_BLE_DEVICE_TTL_MS,\n THIRD_PARTY_BLE_POWER_ON_TIMEOUT_MS,\n THIRD_PARTY_BLE_SCAN_DURATION_MS,\n THIRD_PARTY_BLE_SCAN_IDLE_STOP_MS,\n} from './constants';\n\nimport type { ThirdPartyBleAvailability, ThirdPartyBleDeviceInfo } from './types/desktop-api';\nimport type {\n ElectronBleConnectOptions,\n ElectronBleMatch,\n ElectronBleScanOptions,\n} from '@onekeyfe/hwk-adapter-core';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\n/**\n * Subset of @stoprocent/noble we touch. We type as `any` to keep the package\n * installable without the native module — it's loaded lazily inside main().\n */\nexport interface NobleLike {\n state: string;\n on(event: string, handler: (...args: any[]) => void): NobleLike;\n removeListener(event: string, handler: (...args: any[]) => void): NobleLike;\n startScanningAsync(serviceUuids: string[], allowDuplicates: boolean): Promise<void>;\n stopScanningAsync(): Promise<void>;\n stop?(): void;\n /**\n * Connect by id/address with NO scan. Both native backends support this and\n * emit a `discover` for the peripheral as a side effect: Windows synthesizes\n * one for an unknown address (`BLEManager::Connect`, lib/win/src/ble_manager.cc)\n * and macOS resolves it via `retrievePeripheralsWithIdentifiers`\n * (lib/mac/src/ble_manager.mm). Optional so a stub noble can omit it.\n */\n connectAsync?(idOrAddress: string): Promise<NoblePeripheralLike | undefined>;\n cancelConnect?(idOrAddress: string): void;\n reset?(): Promise<void>;\n}\n\nexport interface NoblePeripheralLike {\n id: string;\n // The full noble advertisement. We capture every field noble surfaces so\n // the host can hunt for a cross-transport identity (e.g. a device serial\n // baked into manufacturerData) without another scan.\n advertisement: {\n localName?: string;\n serviceUuids?: string[];\n manufacturerData?: Buffer;\n serviceData?: Array<{ uuid: string; data: Buffer }>;\n txPowerLevel?: number;\n serviceSolicitationUuids?: string[];\n };\n /** Some noble builds expose the BLE MAC/address separately from `id`. */\n address?: string;\n addressType?: string;\n connectable?: boolean;\n rssi: number;\n state: string;\n connectAsync(): Promise<void>;\n cancelConnect?(): void;\n disconnectAsync(): Promise<void>;\n discoverSomeServicesAndCharacteristicsAsync(\n serviceUuids: string[],\n characteristicUuids: string[]\n ): Promise<{ characteristics: NobleCharacteristicLike[] }>;\n /** Read live RSSI from the connected peripheral. Returns dBm. */\n updateRssiAsync?(): Promise<number>;\n on(event: string, handler: (...args: any[]) => void): NoblePeripheralLike;\n removeListener(event: string, handler: (...args: any[]) => void): NoblePeripheralLike;\n}\n\nexport interface NobleCharacteristicLike {\n uuid: string;\n subscribeAsync(): Promise<void>;\n unsubscribeAsync(): Promise<void>;\n writeAsync(data: Buffer, withoutResponse: boolean): Promise<void>;\n on(\n event: 'data',\n handler: (data: Buffer, isNotification: boolean) => void\n ): NobleCharacteristicLike;\n removeListener(\n event: 'data',\n handler: (data: Buffer, isNotification: boolean) => void\n ): NobleCharacteristicLike;\n}\n\nexport type NobleFactory = () => NobleLike;\n\nconst DEFAULT_NOBLE_FACTORY: NobleFactory = () => {\n // Lazy require so packagers don't bundle the native module at import time.\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const noble = require('@stoprocent/noble') as NobleLike;\n return noble;\n};\n\ninterface DeviceEntry {\n /** Opaque partition key from the caller; this handler never interprets it. */\n vendor?: string;\n write?: ElectronBleConnectOptions['write'];\n peripheral: NoblePeripheralLike;\n writeChar?: NobleCharacteristicLike;\n notifyChar?: NobleCharacteristicLike;\n notifyHandler?: (data: Buffer, isNotification: boolean) => void;\n disconnectHandler?: () => void;\n}\n\nconst normalizeUuid = (uuid: string): string => uuid.replace(/-/g, '').toLowerCase();\n\n/**\n * Does this advertisement belong to the vendor that asked? Stands in for the\n * service-UUID scan filter, which we cannot use (see `scan`). The criteria are\n * supplied by the caller, so no vendor knowledge lives here: a peripheral\n * matches on an advertised service UUID, or on a local name that satisfies\n * every name pattern.\n */\nconst matchesPeripheral = (p: NoblePeripheralLike, match?: ElectronBleMatch): boolean => {\n if (!match) return false;\n const adv = p.advertisement ?? {};\n const advertised = adv.serviceUuids ?? [];\n if (\n match.serviceUuids?.length &&\n advertised.some(uuid =>\n match.serviceUuids?.some(wanted => normalizeUuid(wanted) === normalizeUuid(uuid))\n )\n ) {\n return true;\n }\n const name = adv.localName;\n if (!match.namePatterns?.length || !name) return false;\n return match.namePatterns.every(pattern => new RegExp(pattern, 'i').test(name));\n};\n\n/**\n * Map a noble peripheral to the serializable info we ship over IPC. Buffers\n * are hex-encoded so they survive the structured-clone boundary, and every\n * advertisement field is forwarded — the renderer/connector decides which\n * one is a usable cross-transport identity.\n */\nconst peripheralToInfo = (p: NoblePeripheralLike): ThirdPartyBleDeviceInfo => {\n const adv = p.advertisement ?? {};\n return {\n id: p.id,\n name: adv.localName,\n localName: adv.localName,\n rssi: p.rssi,\n isConnectable: p.connectable ?? null,\n advertisedServiceUuids: adv.serviceUuids,\n serviceSolicitationUuids: adv.serviceSolicitationUuids,\n txPowerLevel: adv.txPowerLevel,\n manufacturerDataHex: adv.manufacturerData\n ? Buffer.from(adv.manufacturerData).toString('hex')\n : undefined,\n serviceData: adv.serviceData?.map(entry => ({\n uuid: entry.uuid,\n dataHex: Buffer.from(entry.data).toString('hex'),\n })),\n address: p.address,\n addressType: p.addressType,\n state: p.state,\n };\n};\n\n/**\n * Sleep helper without taking a dep on timers/promises. Microtask-friendly.\n */\nconst delay = (ms: number): Promise<void> => new Promise(resolve => setTimeout(resolve, ms));\n\n// Radio-settle wait between stopping the scan and opening a GATT connection.\nconst BLE_CONNECT_SETTLE_MS = 300;\n// Hard cap on the connect — noble has none, so a stale bond hangs forever\n// without this. Set to the Bluetooth SMP (Security Manager) pairing timeout\n// (30s, the OS pairing dialog's own limit) + 1s, so a real first-time pairing\n// is never cut off before the system itself gives up.\nconst BLE_CONNECT_TIMEOUT_MS = 31_000;\n// Cap on a cleanup disconnectAsync — it hangs on a just-failed connect.\nconst BLE_DISCONNECT_TIMEOUT_MS = 2_000;\n\n/** Floor between noble rebuilds, so a persistent failure can't thrash. */\nconst NOBLE_RECOVER_COOLDOWN_MS = 10_000;\n\nexport interface NobleBleHandlerOptions {\n /** Override for tests; defaults to `require('@stoprocent/noble')`. */\n nobleFactory?: NobleFactory;\n /** Override the overall connect timeout (tests only; defaults to 31s). */\n connectTimeoutMs?: number;\n logger?: BleDebugLogger;\n}\n\n/**\n * Core BLE logic, decoupled from Electron's IPC layer so it can be unit\n * tested with a fake noble. Mirrors the OneKey `noble-ble-handler.ts`\n * pattern (a single class that owns the peripheral cache + disconnect\n * callbacks), but trimmed to the minimum surface we expose.\n */\nexport class NobleBleHandler {\n private _noble: NobleLike | undefined;\n\n private readonly _factory: NobleFactory;\n\n private readonly _connectTimeoutMs: number;\n\n private readonly _logger?: NobleBleHandlerOptions['logger'];\n\n private readonly _discovered = new Map<string, NoblePeripheralLike>();\n\n // id -> last advertisement time (snapshot TTL).\n private readonly _lastSeen = new Map<string, number>();\n\n private readonly _connected = new Map<string, DeviceEntry>();\n\n private _discoverHandler?: (peripheral: NoblePeripheralLike) => void;\n\n private _scanning = false;\n\n private _idleStopTimer?: ReturnType<typeof setTimeout>;\n\n private _onNotification?: (id: string, hexData: string) => void;\n\n private _onDeviceDisconnected?: (id: string) => void;\n\n private _initialized = false;\n\n private _disposed = false;\n\n private _disposePromise?: Promise<void>;\n\n private _releasePromise?: Promise<void>;\n\n private _initPromise?: Promise<void>;\n\n private readonly _nobleInstances = new Set<NobleLike>();\n\n private readonly _pendingCancellations = new Set<() => void>();\n\n private readonly _connectAttempts = new Set<{\n id: string;\n abandon: (error: Error) => void;\n cancelNative: () => void;\n settled: Promise<unknown>;\n }>();\n\n private _nativeReleased = false;\n\n private _lastNobleRecoverAt?: number;\n\n /** The connect currently in flight, so cancelPairing can abandon it. */\n private _activeConnect?: { id: string; abandon: (error: Error) => void };\n\n constructor(options: NobleBleHandlerOptions = {}) {\n this._factory = options.nobleFactory ?? DEFAULT_NOBLE_FACTORY;\n this._connectTimeoutMs = options.connectTimeoutMs ?? BLE_CONNECT_TIMEOUT_MS;\n this._logger = options.logger;\n }\n\n setNotificationListener(handler: (id: string, hexData: string) => void): void {\n this._onNotification = handler;\n }\n\n setDisconnectedListener(handler: (id: string) => void): void {\n this._onDeviceDisconnected = handler;\n }\n\n async init(): Promise<void> {\n this._assertActive();\n if (this._initialized) return;\n if (this._initPromise) return this._initPromise;\n this._initPromise = (async () => {\n this._noble ??= this._factory();\n this._nobleInstances.add(this._noble);\n this._discoverHandler ??= peripheral => {\n this._discovered.set(peripheral.id, peripheral);\n this._lastSeen.set(peripheral.id, Date.now());\n };\n this._noble.removeListener('discover', this._discoverHandler);\n this._noble.on('discover', this._discoverHandler);\n await this._waitForPoweredOn(THIRD_PARTY_BLE_POWER_ON_TIMEOUT_MS);\n this._assertActive();\n this._initialized = true;\n })();\n try {\n await this._initPromise;\n } finally {\n this._initPromise = undefined;\n }\n }\n\n async checkAvailability(): Promise<ThirdPartyBleAvailability> {\n this._assertActive();\n if (!this._noble) {\n try {\n this._noble = this._factory();\n this._nobleInstances.add(this._noble);\n } catch {\n return { available: false, state: 'unsupported', initialized: false };\n }\n }\n const state = this._noble?.state ?? 'unknown';\n return {\n available: state === 'poweredOn',\n state,\n initialized: this._initialized,\n };\n }\n\n /**\n * Lazy-start a continuous scan and return the current snapshot immediately.\n *\n * Scans UNFILTERED and applies the caller's match criteria in `_snapshot()` instead. A\n * service-UUID filter cannot be used here: noble's Windows backend applies it\n * per RECEIVED PACKET (`BLEManager::OnScanResult`, lib/win/src/ble_manager.cc),\n * and a Safe 7's ADV packet carries only its name — the service UUID lives in\n * the scan response, which arrives as a separate, irregularly-timed event. So\n * a filtered scan drops every ADV packet and the device appears to be\n * undiscoverable for minutes at a time while it is plainly on air. (OneKey's\n * own devices do advertise their service UUID, which is why the same filter is\n * safe in `hd-transport-electron` and was copied here by mistake.)\n */\n async scan(options?: ElectronBleScanOptions): Promise<ThirdPartyBleDeviceInfo[]> {\n await this.init();\n if (!this._scanning) {\n this._scanning = true;\n // allowDuplicates=true keeps advertisements flowing so we can age out gone devices.\n try {\n await this._requireNoble().startScanningAsync([], true);\n // warn: unfiltered scan on the noble instance shared with the OneKey\n // handler — must always be visible for cross-correlation.\n this._log('warn', 'scan.start', {\n ignoredServiceUuids: options?.serviceUuids,\n allowDuplicates: true,\n });\n } catch (error) {\n this._scanning = false;\n this._log('warn', 'scan.start.error', { error: String(error) });\n await this._recoverNobleIfStuck(String(error));\n }\n }\n this._assertActive();\n this._armIdleStop();\n const devices = this._snapshot(options);\n // raw vs kept. An empty result now has two very different causes and the log\n // must say which: raw=0 means nothing is on air at all (radio, or the device\n // simply is not advertising); raw>0 with kept=0 means WE are dropping it —\n // the caller's match criteria are wrong. Without this the two look identical.\n if (devices.length === 0) {\n // Counts only: the scan is unfiltered, so naming what it saw would put\n // bystanders' devices in a log the user hands to support.\n this._log('warn', 'scan.empty', {\n raw: this._discovered.size,\n kept: 0,\n named: [...this._discovered.values()].filter(p => p.advertisement?.localName).length,\n });\n }\n return devices;\n }\n\n /**\n * Current in-range devices for the asking vendor, dropping any that aged past\n * the liveness TTL. The match test replaces the service-UUID scan filter we cannot use\n * (see `scan`): it matches the name from the ADV packet, or the service UUID\n * once a scan response has merged into the same peripheral.\n *\n * Note the TTL only prunes what the CALLER sees. `_discovered` is a cache, not\n * the source of truth for reachability — a device missing from here can still\n * be connected to by id (`_directConnect`).\n */\n private _snapshot(options?: ElectronBleScanOptions): ThirdPartyBleDeviceInfo[] {\n const now = Date.now();\n const result: ThirdPartyBleDeviceInfo[] = [];\n for (const [id, peripheral] of this._discovered) {\n if (now - (this._lastSeen.get(id) ?? 0) > THIRD_PARTY_BLE_DEVICE_TTL_MS) {\n this._discovered.delete(id);\n this._lastSeen.delete(id);\n continue;\n }\n const match = options?.match ?? { serviceUuids: options?.serviceUuids };\n if (!matchesPeripheral(peripheral, match)) continue;\n result.push(peripheralToInfo(peripheral));\n }\n // A device WE hold a link to stops advertising (standard BLE), so it ages\n // out of the scan cache above within the TTL — exactly while keep-alive\n // holds the link for up to minutes. Without this merge, the one device the\n // user is actively using vanishes from the device list. Field-verified:\n // pairing/THP handshake alone does NOT silence a Safe 7; holding the\n // connection does.\n for (const [id, entry] of this._connected) {\n if (entry.vendor !== options?.vendor) continue;\n if (result.some(info => info.id === id)) continue;\n result.push(peripheralToInfo(entry.peripheral));\n }\n return result;\n }\n\n /** A noble instance with its own bindings, so a stuck one can be replaced. */\n private _createFreshNoble(): NobleLike {\n const candidate = this._factory() as NobleLike & {\n withBindings?: () => NobleLike;\n };\n return typeof candidate.withBindings === 'function' ? candidate.withBindings() : candidate;\n }\n\n /**\n * Rebuild noble when its adapter state is stuck. Re-enumerating the Windows\n * BLE stack (pairing, or removing the device from OS settings) can catch\n * noble's RadioWatcher mid-churn: it latches `unsupported` and never\n * re-evaluates, so every later scan fails until the process restarts. Fresh\n * bindings restart that watcher, which is the in-process equivalent of the\n * app restart that is otherwise the only cure.\n */\n private async _recoverNobleIfStuck(reason: string): Promise<void> {\n if (this._disposed) return;\n const state = this._noble?.state;\n if (state === 'poweredOn' || !this._initialized) return;\n // Never tear down bindings out from under a live link.\n if (this._connected.size > 0) {\n this._log('warn', 'noble.recover.skip', {\n reason,\n state,\n connected: this._connected.size,\n });\n return;\n }\n const now = Date.now();\n if (this._lastNobleRecoverAt && now - this._lastNobleRecoverAt < NOBLE_RECOVER_COOLDOWN_MS) {\n return;\n }\n this._lastNobleRecoverAt = now;\n this._log('warn', 'noble.recover.start', { reason, state });\n try {\n const previous = this._noble;\n if (previous && this._discoverHandler) {\n previous.removeListener('discover', this._discoverHandler);\n }\n // The default factory returns noble's module singleton — the very object\n // that is stuck — so rebuilding needs `withBindings()`, which mints a new\n // instance (and with it a new RadioWatcher). Injected factories are\n // assumed to already hand back a fresh instance.\n const fresh = this._createFreshNoble();\n this._noble = fresh;\n this._nobleInstances.add(fresh);\n if (this._discoverHandler) {\n fresh.on('discover', this._discoverHandler);\n }\n this._scanning = false;\n this._discovered.clear();\n this._lastSeen.clear();\n await this._waitForPoweredOn(THIRD_PARTY_BLE_POWER_ON_TIMEOUT_MS);\n this._log('warn', 'noble.recover.done', { state: this._noble?.state });\n } catch (error) {\n // Recovery is best-effort; the caller already reported the scan failure.\n this._log('warn', 'noble.recover.error', { error: String(error) });\n }\n }\n\n private _armIdleStop(): void {\n if (this._disposed) return;\n this._clearIdleStop();\n this._idleStopTimer = setTimeout(() => {\n void this._stopContinuousScan();\n }, THIRD_PARTY_BLE_SCAN_IDLE_STOP_MS);\n }\n\n private _clearIdleStop(): void {\n if (this._idleStopTimer) {\n clearTimeout(this._idleStopTimer);\n this._idleStopTimer = undefined;\n }\n }\n\n /** Stop scanning but keep the discovered cache (used before connect). */\n private async _pauseScan(): Promise<void> {\n this._clearIdleStop();\n if (!this._scanning) return;\n this._scanning = false;\n await this._noble?.stopScanningAsync().catch(() => undefined);\n }\n\n /** Stop scanning and forget discovered devices (idle timeout / teardown). */\n private async _stopContinuousScan(): Promise<void> {\n await this._pauseScan();\n this._discovered.clear();\n this._lastSeen.clear();\n }\n\n /**\n * Stops the process-wide scan no matter which vendor asked. Scan *results*\n * are filtered per vendor, but the radio is not: one vendor's stopScan ends\n * the other's discovery too. That is safe only because the adapter job queue\n * serializes discovery across vendors, so two are never scanning at once.\n * Anything that breaks that — a background presence probe, say — needs\n * per-vendor refcounting here first.\n */\n async stopScan(): Promise<void> {\n await this._stopContinuousScan();\n }\n\n /**\n * Look up a previously-scanned device by id (no extra BLE traffic).\n * Returns null if the device hasn't been seen by a recent scan.\n */\n getDevice(id: string): ThirdPartyBleDeviceInfo | null {\n const p = this._discovered.get(id);\n if (!p) return null;\n return peripheralToInfo(p);\n }\n\n /**\n * Read the current RSSI (in dBm) for a connected peripheral. Requires\n * the device to be connected — noble can't read RSSI off a scan-only\n * peripheral. Falls back to the cached scan-time rssi when the noble\n * peripheral doesn't expose updateRssiAsync.\n */\n async readRssi(id: string): Promise<number> {\n const entry = this._requireEntry(id);\n if (entry.peripheral.updateRssiAsync) {\n return entry.peripheral.updateRssiAsync();\n }\n return entry.peripheral.rssi;\n }\n\n /**\n * Abort the in-flight pairing flow: abandon a connect that is still running,\n * stop scanning, disconnect every peripheral the host currently has open.\n * Caller is responsible for surfacing the cancellation to the upper UI layer.\n *\n * Abandoning the connect is what actually ends the flow. Pairing happens\n * inside connectAsync and the entry only reaches _connected after service\n * discovery, so the loop below never sees the device being paired — without\n * the abandon the caller waits out the full connect timeout, which is sized\n * to the OS pairing window and so feels like a hang.\n */\n async cancelPairing(): Promise<void> {\n const attempt = this._activeConnect;\n if (attempt) {\n this._activeConnect = undefined;\n // connect()'s catch tears down the half-open peripheral from _discovered.\n attempt.abandon(new Error(`connect cancelled: ${attempt.id}`));\n }\n await this.stopScan();\n for (const id of Array.from(this._connected.keys())) {\n await this.disconnect(id).catch(() => undefined);\n }\n }\n\n /**\n * Scan for a specific peripheral id and resolve THE MOMENT it's discovered,\n * stopping the scan immediately (don't wait out the full window). The fast\n * reconnect path for a stored connectId when the device IS advertising.\n *\n * This used to be the only reconnect path, on two assumptions that are both\n * false: that noble cannot connect by id without a scan (it can — see\n * `_directConnect`), and that \"the device advertises continuously\" (a bonded\n * Safe 7 does not — it holds the link and goes silent). Callers must fall\n * back to `_directConnect` when this returns undefined.\n */\n private async _scanUntilFound(\n id: string,\n timeoutMs: number\n ): Promise<NoblePeripheralLike | undefined> {\n await this.init();\n const existing = this._discovered.get(id);\n if (existing) return existing;\n const noble = this._requireNoble();\n return new Promise<NoblePeripheralLike | undefined>(resolve => {\n let done = false;\n const finish = (p?: NoblePeripheralLike) => {\n if (done) return;\n done = true;\n this._pendingCancellations.delete(cancel);\n clearTimeout(timer);\n noble.removeListener('discover', onDiscover);\n void noble.stopScanningAsync().catch(() => undefined);\n resolve(p);\n };\n const onDiscover = (peripheral: NoblePeripheralLike) => {\n this._discovered.set(peripheral.id, peripheral);\n if (peripheral.id === id) finish(peripheral);\n };\n const timer = setTimeout(() => finish(this._discovered.get(id)), timeoutMs);\n const cancel = () => finish();\n this._pendingCancellations.add(cancel);\n noble.on('discover', onDiscover);\n // Unfiltered, for the same reason as `scan()` — a service-UUID filter\n // drops the Safe 7's ADV packets outright on Windows.\n void noble.startScanningAsync([], false).catch(() => finish());\n });\n }\n\n /**\n * Connect by id with no scan and no advertisement.\n *\n * This is the ONLY path that reaches a device which is connected but silent.\n * A linked peripheral stops advertising while it HOLDS A LINK (standard BLE; a Safe 7's\n * screen says \"wait connection\") — field-verified: bonding/THP handshake\n * alone does NOT silence it, holding the connection does. So while a link is\n * up, no amount of scanning will rediscover it — `_scanUntilFound` alone\n * dead-ends with \"device not found\" on a device that is sitting right there,\n * connected and reachable.\n *\n * noble supports this: `noble.connectAsync(id)` needs no prior `discover`,\n * because both native backends materialize the peripheral themselves (Windows\n * synthesizes one for an unknown address, macOS retrieves it by identifier)\n * and then emit a `discover`, which our own handler turns back into a\n * `_discovered` entry. OneKey's own noble handler calls this \"direct\n * connection mode\"; Trezor Suite's equivalent is asking the adapter for its\n * peripheral list instead of keeping a cache.\n *\n * Returns undefined (not throw) so the caller reports the normal\n * \"device not found\" rather than a confusing noble-internal error.\n */\n private async _directConnect(id: string): Promise<NoblePeripheralLike | undefined> {\n const noble = this._requireNoble();\n if (typeof noble.connectAsync !== 'function') {\n // An old/stub noble. Say so explicitly — otherwise this is indistinguishable\n // in the log from \"the device wasn't there\", which is a different problem.\n this._log('warn', 'connect.direct.unavailable', { id });\n return undefined;\n }\n // warn, not info: this call is the load-bearing assumption of the whole fix —\n // that noble can still reach a bonded device which has STOPPED ADVERTISING.\n // It has never been proven against real hardware, so it must always be in the\n // log, not only when debug logging happens to be on.\n this._log('warn', 'connect.direct.start', { id });\n const startedAt = Date.now();\n try {\n // Bounded by the overall connect timeout in `connect()` — noble itself has\n // none, and the macOS backend silently never resolves when it cannot\n // retrieve the peripheral.\n const peripheral = await noble.connectAsync(id);\n const resolved = peripheral ?? this._discovered.get(id);\n this._log('warn', 'connect.direct.done', {\n id,\n elapsedMs: Date.now() - startedAt,\n found: Boolean(resolved),\n // The one field that says whether the fix actually worked: an open link,\n // or merely an object. Anything other than 'connected' is a failure that\n // would otherwise surface later as a confusing service-discovery error.\n state: resolved?.state,\n fromNoble: Boolean(peripheral),\n });\n return resolved;\n } catch (error) {\n this._log('warn', 'connect.direct.error', {\n id,\n elapsedMs: Date.now() - startedAt,\n error: String(error),\n });\n return undefined;\n }\n }\n\n // noble's disconnectAsync hangs on a peripheral whose connect just failed (it\n // waits for a CoreBluetooth disconnect event that never comes); bound it so a\n // cleanup disconnect can't hang the connect flow.\n private async _safeDisconnect(peripheral: NoblePeripheralLike): Promise<void> {\n if (this._nativeReleased) return;\n let timeout: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n peripheral.disconnectAsync().catch(() => undefined),\n new Promise<void>(resolve => {\n timeout = setTimeout(resolve, BLE_DISCONNECT_TIMEOUT_MS);\n }),\n ]);\n } finally {\n clearTimeout(timeout);\n }\n }\n\n // noble has no connect timeout, so a stale bond hangs anywhere — connectAsync\n // OR the post-connect (encrypted) service discovery. One overall timeout\n // covers the whole flow. Two distinct failures reach the connector: a `timed\n // out` reject (device unreachable) vs a connectAsync `connection failed`\n // reject (link refused / stale bond) — mapped to different error codes there.\n async connect(\n id: string,\n options: ElectronBleConnectOptions\n ): Promise<{ id: string; name?: string }> {\n if (\n !options ||\n !options.vendor ||\n ![options.serviceUuid, options.writeUuid, options.notifyUuid].every(\n uuid => typeof uuid === 'string' && /^[0-9a-f]{32}$/i.test(normalizeUuid(uuid))\n )\n ) {\n throw new Error('Invalid BLE GATT profile');\n }\n this._assertActive();\n // Promise.race only times out the CALLER — it cannot cancel the in-flight\n // _connectInner. Native cancellation is handled separately during disposal.\n // Without the claim token a late\n // connectAsync success would still discover services and commit to\n // _connected: an open GATT link nobody owns, and since a linked Safe 7\n // stops advertising, every retry then dead-ends until app restart. The\n // token flags the attempt as abandoned so a late success tears the link\n // down instead of committing it.\n const claim: { abandoned: boolean; cancelNative?: () => void } = { abandoned: false };\n // The timeout is one way to abandon the attempt; cancelPairing is the other,\n // so the rejection is hoisted out of the timer and both share it.\n let abandon!: (error: Error) => void;\n const abandoned = new Promise<never>((_, reject) => {\n abandon = (error: Error) => {\n claim.abandoned = true;\n reject(error);\n };\n });\n const timer = setTimeout(\n () => abandon(new Error(`connect timed out after ${this._connectTimeoutMs}ms`)),\n this._connectTimeoutMs\n );\n const attempt = {\n id,\n abandon,\n cancelNative: () => claim.cancelNative?.(),\n settled: Promise.resolve<unknown>(undefined),\n };\n this._activeConnect = attempt;\n this._connectAttempts.add(attempt);\n const nativeOperation = this._connectInner(id, claim, options);\n const caller = (async () => {\n try {\n return await Promise.race([nativeOperation, abandoned]);\n } catch (error) {\n const peripheral = this._discovered.get(id);\n if (peripheral) await this._safeDisconnect(peripheral);\n throw error;\n } finally {\n clearTimeout(timer);\n if (this._activeConnect === attempt) this._activeConnect = undefined;\n }\n })();\n // A rejected caller can still have a native connect or disconnect in flight.\n attempt.settled = Promise.allSettled([nativeOperation, caller]).finally(() => {\n this._connectAttempts.delete(attempt);\n });\n return caller;\n }\n\n private async _connectInner(\n id: string,\n claim: { abandoned: boolean; cancelNative?: () => void },\n options: ElectronBleConnectOptions\n ): Promise<{ id: string; name?: string }> {\n await this.init();\n // Stop scanning (keep the cache) and let the radio settle before connecting.\n await this._pauseScan();\n await delay(BLE_CONNECT_SETTLE_MS);\n this._assertActive();\n // Which of the three routes got us a peripheral is THE diagnostic for this\n // whole area: a cache hit means the happy path; a scan hit means the device\n // was still advertising; `direct` means it had gone silent and only\n // connect-by-id could reach it; `none` means we are back to the old dead end.\n let route: 'cache' | 'scan' | 'direct' | 'none' = 'cache';\n let peripheral = this._discovered.get(id);\n if (!peripheral) {\n route = 'scan';\n peripheral = await this._scanUntilFound(id, THIRD_PARTY_BLE_SCAN_DURATION_MS);\n }\n if (!peripheral) {\n route = 'direct';\n }\n if (!peripheral) {\n // Last resort, and the only path that works for a bonded-but-silent\n // device. See _directConnect.\n //\n // Deliberately AFTER the scan, even though that costs the full scan window\n // on this path: macOS's noble backend never resolves connect-by-id for a\n // peripheral CoreBluetooth cannot retrieve (it drops the failure on the\n // floor — `NobleMac::Connect`, lib/mac/src/noble_mac.mm), so trying it\n // first would risk hanging where a scan would simply have found the device.\n const native = this._requireNoble();\n claim.cancelNative = () => native.cancelConnect?.(id);\n peripheral = await this._directConnect(id);\n }\n if (!peripheral) {\n // Every route exhausted. Log what we could see, so \"device not found\" is\n // never again a dead end with nothing behind it: `discoveredCount` says\n // whether the scan saw ANY BLE traffic (0 = radio/scan problem) and\n // `trezorCount` whether the name/uuid filter is rejecting our own device.\n // Counts only — see scan.empty. The target id is ours to log; the rest of\n // the unfiltered scan is not.\n this._log('warn', 'connect.notFound', {\n id,\n route: 'none',\n discoveredCount: this._discovered.size,\n });\n throw new Error(`BLE device not found: ${id}`);\n }\n\n // Checked after every await that can outlive the caller's timeout. The\n // rejection thrown here is unobservable (Promise.race already settled) —\n // its only job is to stop the flow before it commits an unowned link.\n const abortIfAbandoned = async (stage: string) => {\n if (!claim.abandoned && !this._disposed) return;\n // Tear down only a link nobody owns: if a previous connect still holds\n // this id in _connected, its keep-alive timers manage the link.\n if (peripheral && peripheral.state === 'connected' && !this._connected.has(id)) {\n await this._safeDisconnect(peripheral);\n }\n this._log('warn', 'connect.abandoned', { id, route, stage });\n throw new Error(`connect abandoned after timeout: ${id}`);\n };\n await abortIfAbandoned('resolve');\n\n const wasConnected = peripheral.state === 'connected';\n const connectingPeripheral = peripheral;\n const native = this._requireNoble();\n claim.cancelNative = () => {\n if (connectingPeripheral.state === 'connecting' && connectingPeripheral.cancelConnect) {\n connectingPeripheral.cancelConnect();\n } else {\n native.cancelConnect?.(id);\n }\n };\n // The single line that explains any BLE connect after the fact.\n this._log('warn', 'connect.route', {\n id,\n route,\n wasConnected,\n name: peripheral.advertisement?.localName,\n });\n if (!wasConnected) {\n await peripheral.connectAsync();\n await abortIfAbandoned('link');\n }\n\n try {\n const uuids = {\n service: options.serviceUuid,\n write: options.writeUuid,\n notify: options.notifyUuid,\n };\n const { characteristics } = await peripheral.discoverSomeServicesAndCharacteristicsAsync(\n [uuids.service],\n [uuids.write, uuids.notify]\n );\n const writeUuid = normalizeUuid(uuids.write);\n const notifyUuid = normalizeUuid(uuids.notify);\n const writeChar = characteristics.find(c => normalizeUuid(c.uuid) === writeUuid);\n const notifyChar = characteristics.find(c => normalizeUuid(c.uuid) === notifyUuid);\n if (!writeChar || !notifyChar) {\n throw new Error(`BLE characteristics not found on device ${id}`);\n }\n // Last gate before commit: service discovery can also outlast the timeout.\n await abortIfAbandoned('discovery');\n\n const disconnectHandler = () => {\n // One peripheral object outlives many connections. Only the handler\n // the current entry owns may act: a handler left over from an earlier\n // link must not report the current one as unexpectedly dropped.\n if (this._connected.get(id)?.disconnectHandler !== disconnectHandler) return;\n this._cleanupDevice(id, /* unexpected */ true);\n };\n peripheral.on('disconnect', disconnectHandler);\n\n this._connected.set(id, {\n peripheral,\n writeChar,\n notifyChar,\n disconnectHandler,\n vendor: options.vendor,\n write: options.write,\n });\n this._log('info', 'connect.done', { id, name: peripheral.advertisement.localName });\n return { id, name: peripheral.advertisement.localName };\n } catch (error) {\n // Discovery failed after we opened the GATT connection — disconnect it\n // (bounded) so we don't leak it. Only if this call connected it.\n if (!wasConnected) await this._safeDisconnect(peripheral);\n throw error;\n }\n }\n\n async disconnect(id: string): Promise<void> {\n const entry = this._connected.get(id);\n if (!entry) return;\n if (entry.disconnectHandler) {\n // Suppress the unexpected-disconnect event for explicit disconnects.\n entry.peripheral.removeListener('disconnect', entry.disconnectHandler);\n }\n try {\n await entry.peripheral.disconnectAsync();\n } catch (error) {\n this._log('warn', 'disconnect.error', { id, error: String(error) });\n }\n this._cleanupDevice(id, /* unexpected */ false);\n }\n\n async subscribe(id: string): Promise<void> {\n const entry = this._requireEntry(id);\n if (!entry.notifyChar) throw new Error(`BLE notify characteristic missing for ${id}`);\n if (entry.notifyHandler) return;\n const handler = (data: Buffer) => {\n this._onNotification?.(id, data.toString('hex'));\n };\n entry.notifyHandler = handler;\n entry.notifyChar.on('data', handler);\n await entry.notifyChar.subscribeAsync();\n }\n\n async unsubscribe(id: string): Promise<void> {\n const entry = this._connected.get(id);\n if (!entry?.notifyChar) return;\n if (entry.notifyHandler) {\n entry.notifyChar.removeListener('data', entry.notifyHandler);\n entry.notifyHandler = undefined;\n }\n try {\n await entry.notifyChar.unsubscribeAsync();\n } catch (error) {\n this._log('warn', 'unsubscribe.error', { id, error: String(error) });\n }\n }\n\n async write(id: string, hexData: string): Promise<void> {\n const entry = this._requireEntry(id);\n if (!entry.writeChar) throw new Error(`BLE write characteristic missing for ${id}`);\n const buffer = Buffer.from(hexData, 'hex');\n const framing = entry.write;\n if (!framing) throw new Error(`No BLE write framing recorded for ${id}`);\n\n if (framing.mode === 'raw') {\n // Framing that carries its own length and sequence; padding corrupts it.\n // `maxLength` bounds the write without truncating a negotiated frame —\n // for Ledger the size is negotiated per connection (0x08 handshake) and\n // reported in a single byte, so 255 is the most that protocol can ask for.\n const maxLength = framing.maxLength ?? buffer.length;\n if (!/^(?:[0-9a-f]{2})+$/i.test(hexData) || buffer.length > maxLength) {\n throw new Error(`Invalid BLE frame for ${entry.vendor ?? 'device'}`);\n }\n await entry.writeChar.writeAsync(buffer, false);\n return;\n }\n\n const chunkSize = framing.chunkSize;\n if (!chunkSize) throw new Error(`Padded BLE writes need a chunkSize for ${id}`);\n for (let offset = 0; offset < buffer.length; offset += chunkSize) {\n this._assertActive();\n const slice = buffer.subarray(offset, offset + chunkSize);\n // Padded framing means every packet is the full chunk size, zero-filled.\n // Firmware that wants padding silently drops a short final packet → no response →\n // RetriesExceeded. Matches trezor-suite transport-bluetooth.\n const chunk = Buffer.alloc(chunkSize);\n slice.copy(chunk);\n // OneKey uses writeWithResponse for stability; mirror that.\n await entry.writeChar.writeAsync(chunk, false);\n if (offset + chunkSize < buffer.length && framing.chunkDelayMs) {\n await delay(framing.chunkDelayMs);\n }\n }\n }\n\n /** Retire a renderer's handler without stopping a process-wide native manager. */\n dispose(): Promise<void> {\n if (this._disposePromise) return this._disposePromise;\n this._disposed = true;\n this._clearIdleStop();\n this._scanning = false;\n this._onNotification = undefined;\n this._onDeviceDisconnected = undefined;\n const connections = Array.from(this._connectAttempts);\n for (const attempt of connections) {\n attempt.abandon(new Error('Desktop BLE is shutting down'));\n try {\n attempt.cancelNative();\n } catch (error) {\n this._log('warn', 'dispose.cancelConnect.error', { error: String(error) });\n }\n }\n for (const cancel of this._pendingCancellations) cancel();\n if (this._noble && this._discoverHandler) {\n this._noble.removeListener('discover', this._discoverHandler);\n }\n const entries = Array.from(this._connected.entries());\n for (const [id, entry] of entries) {\n if (entry.disconnectHandler) {\n entry.peripheral.removeListener('disconnect', entry.disconnectHandler);\n }\n this._cleanupDevice(id, false);\n }\n let timeout: ReturnType<typeof setTimeout> | undefined;\n this._disposePromise = (async () => {\n try {\n await Promise.race([\n Promise.allSettled([\n ...connections.map(attempt => attempt.settled),\n ...Array.from(this._nobleInstances, async instance => instance.stopScanningAsync()),\n ...entries.map(async ([, entry]) => {\n let unsubscribeTimeout: ReturnType<typeof setTimeout> | undefined;\n try {\n await Promise.race([\n entry.notifyChar?.unsubscribeAsync().catch(() => undefined),\n new Promise<void>(resolve => {\n unsubscribeTimeout = setTimeout(resolve, 250);\n }),\n ]);\n } finally {\n clearTimeout(unsubscribeTimeout);\n await this._safeDisconnect(entry.peripheral);\n }\n }),\n ]),\n new Promise<void>(resolve => {\n timeout = setTimeout(() => {\n this._log('warn', 'dispose.timeout');\n resolve();\n }, 3500);\n }),\n ]);\n } finally {\n clearTimeout(timeout);\n this._discovered.clear();\n this._lastSeen.clear();\n this._initialized = false;\n }\n })();\n return this._disposePromise;\n }\n\n /**\n * Terminal native release, including instances replaced by adapter recovery.\n * A host sharing Noble must defer stop() until all transports have disposed,\n * and deduplicate instances passed to releaseNoble across those transports.\n */\n disposeForAppQuit(\n releaseNoble: (instance: { stop?(): void }) => void = instance => instance.stop?.()\n ): Promise<void> {\n if (!this._releasePromise) {\n this._releasePromise = this.dispose().finally(() => {\n this._nativeReleased = true;\n let releaseError: Error | undefined;\n for (const instance of this._nobleInstances) {\n try {\n releaseNoble(instance);\n } catch (error) {\n releaseError = error instanceof Error ? error : new Error(String(error));\n }\n }\n this._nobleInstances.clear();\n if (releaseError) throw releaseError;\n this._log('info', 'dispose.native.done');\n });\n }\n return this._releasePromise;\n }\n\n private _assertActive(): void {\n if (this._disposed) throw new Error('Desktop BLE is shutting down');\n }\n\n private _cleanupDevice(id: string, unexpected: boolean): void {\n const entry = this._connected.get(id);\n if (!entry) return;\n if (entry.notifyChar && entry.notifyHandler) {\n entry.notifyChar.removeListener('data', entry.notifyHandler);\n }\n // Release this connection's own disconnect listener. Without it the\n // handler stays attached to a peripheral we no longer hold, and a later\n // explicit disconnect of the same device is reported as an unexpected one.\n if (entry.disconnectHandler) {\n entry.peripheral.removeListener('disconnect', entry.disconnectHandler);\n }\n this._connected.delete(id);\n if (unexpected) {\n this._log('warn', 'disconnect.unexpected', { id });\n this._onDeviceDisconnected?.(id);\n }\n }\n\n private _requireEntry(id: string): DeviceEntry {\n this._assertActive();\n const entry = this._connected.get(id);\n if (!entry) throw new Error(`BLE device is not connected: ${id}`);\n return entry;\n }\n\n private _requireNoble(): NobleLike {\n this._assertActive();\n if (!this._noble) throw new Error('Desktop BLE: noble was not initialized');\n return this._noble;\n }\n\n private async _waitForPoweredOn(timeoutMs: number): Promise<void> {\n const noble = this._requireNoble();\n if (noble.state === 'poweredOn') return;\n await new Promise<void>((resolve, reject) => {\n const cleanup = () => {\n clearTimeout(timer);\n noble.removeListener('stateChange', handler);\n this._pendingCancellations.delete(cancel);\n };\n const cancel = () => {\n cleanup();\n reject(new Error('Desktop BLE is shutting down'));\n };\n const timer = setTimeout(() => {\n cleanup();\n reject(\n new Error(\n `Desktop BLE: noble did not reach poweredOn within ${timeoutMs}ms (last state: ${noble.state})`\n )\n );\n }, timeoutMs);\n const handler = (state: string) => {\n if (state === 'poweredOn') {\n cleanup();\n resolve();\n } else if (state === 'unsupported' || state === 'unauthorized') {\n cleanup();\n reject(new Error(`Desktop BLE: noble state ${state}`));\n }\n };\n this._pendingCancellations.add(cancel);\n noble.on('stateChange', handler);\n });\n }\n\n private _log(level: BleDebugLogLevel, event: string, data?: Record<string, unknown>): void {\n this._logger?.({\n level,\n scope: 'desktop-noble-ble',\n event,\n data: redactBleDebugLogData(data),\n });\n }\n}\n","import { THIRD_PARTY_BLE_CHANNELS } from './constants';\nimport { NobleBleHandler } from './NobleBleHandler';\n\nimport type { NobleBleHandlerOptions } from './NobleBleHandler';\nimport type { ElectronBleConnectOptions, ElectronBleScanOptions } from '@onekeyfe/hwk-adapter-core';\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nexport { NobleBleHandler } from './NobleBleHandler';\nexport type {\n NobleBleHandlerOptions,\n NobleLike,\n NoblePeripheralLike,\n NobleCharacteristicLike,\n} from './NobleBleHandler';\nexport { THIRD_PARTY_BLE_CHANNELS } from './constants';\nexport type {\n ThirdPartyBleApi,\n ThirdPartyBleAvailability,\n ThirdPartyBleDeviceInfo,\n} from './types/desktop-api';\n\n/** Minimal slice of Electron's `WebContents` we use (kept duck-typed so we\n * don't take a hard dep on `electron`). */\nexport interface WebContentsLike {\n send(channel: string, ...args: unknown[]): void;\n on?(event: string, listener: (...args: any[]) => void): void;\n}\n\n/** Minimal slice of Electron's `ipcMain` we use. */\nexport interface IpcMainLike {\n handle(\n channel: string,\n listener: (event: unknown, ...args: any[]) => Promise<unknown> | unknown\n ): void;\n removeHandler(channel: string): void;\n}\n\nexport interface InitThirdPartyBleSupportOptions extends NobleBleHandlerOptions {\n /** Inject your own `ipcMain` (defaults to `require('electron').ipcMain`). */\n ipcMain?: IpcMainLike;\n}\n\nexport interface ThirdPartyBleSupportHandle {\n handler: NobleBleHandler;\n dispose(): Promise<void>;\n disposeForAppQuit(releaseNoble?: (instance: { stop?(): void }) => void): Promise<void>;\n}\n\nconst DEFAULT_IPC_MAIN: () => IpcMainLike = () => {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { ipcMain } = require('electron') as { ipcMain: IpcMainLike };\n return ipcMain;\n};\n\n/**\n * Wire a `NobleBleHandler` to Electron's IPC so the renderer can drive BLE\n * via `window.desktopApi.trezorBle`. Call once from the main process after\n * `BrowserWindow` is ready.\n *\n * Call dispose() when retiring a renderer and disposeForAppQuit() before Node teardown.\n */\nexport function initThirdPartyBleSupport(\n webContents: WebContentsLike,\n options: InitThirdPartyBleSupportOptions = {}\n): ThirdPartyBleSupportHandle {\n const ipcMain = options.ipcMain ?? DEFAULT_IPC_MAIN();\n const handler = new NobleBleHandler(options);\n let disposed = false;\n\n handler.setNotificationListener((id, hexData) => {\n webContents.send(THIRD_PARTY_BLE_CHANNELS.notification, id, hexData);\n });\n handler.setDisconnectedListener(id => {\n webContents.send(THIRD_PARTY_BLE_CHANNELS.disconnected, id);\n });\n\n const handle = <T>(channel: string, fn: (...args: any[]) => Promise<T> | T): void => {\n ipcMain.handle(channel, async (_event, ...args) => {\n if (disposed) throw new Error('Third-party BLE is shutting down');\n return fn(...args);\n });\n };\n\n handle(THIRD_PARTY_BLE_CHANNELS.scan, (options?: ElectronBleScanOptions) =>\n handler.scan(options)\n );\n handle(THIRD_PARTY_BLE_CHANNELS.stopScan, () => handler.stopScan());\n handle(THIRD_PARTY_BLE_CHANNELS.connect, (id: string, options: ElectronBleConnectOptions) =>\n handler.connect(id, options)\n );\n handle(THIRD_PARTY_BLE_CHANNELS.disconnect, (id: string) => handler.disconnect(id));\n handle(THIRD_PARTY_BLE_CHANNELS.write, (id: string, hexData: string) =>\n handler.write(id, hexData)\n );\n handle(THIRD_PARTY_BLE_CHANNELS.subscribe, (id: string) => handler.subscribe(id));\n handle(THIRD_PARTY_BLE_CHANNELS.unsubscribe, (id: string) => handler.unsubscribe(id));\n handle(THIRD_PARTY_BLE_CHANNELS.availability, () => handler.checkAvailability());\n handle(THIRD_PARTY_BLE_CHANNELS.getDevice, (id: string) => handler.getDevice(id));\n handle(THIRD_PARTY_BLE_CHANNELS.readRssi, (id: string) => handler.readRssi(id));\n handle(THIRD_PARTY_BLE_CHANNELS.cancelPairing, () => handler.cancelPairing());\n\n const removeHandlers = () => {\n if (disposed) return;\n disposed = true;\n for (const channel of Object.values(THIRD_PARTY_BLE_CHANNELS)) {\n ipcMain.removeHandler(channel);\n }\n };\n\n return {\n handler,\n dispose: () => {\n removeHandlers();\n return handler.dispose();\n },\n disposeForAppQuit: releaseNoble => {\n removeHandlers();\n return handler.disposeForAppQuit(releaseNoble);\n },\n };\n}\n"],"mappings":"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","names":["native","options"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@onekeyfe/hwk-desktop-noble-ble",
|
|
3
|
+
"version": "1.2.3-alpha.2",
|
|
4
|
+
"description": "Main-process BLE service (noble) shared by third-party hardware connectors on desktop.",
|
|
5
|
+
"author": "OneKey",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"main": "dist/index.js",
|
|
8
|
+
"module": "dist/index.mjs",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"import": {
|
|
13
|
+
"types": "./dist/index.d.mts",
|
|
14
|
+
"default": "./dist/index.mjs"
|
|
15
|
+
},
|
|
16
|
+
"require": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"./constants": {
|
|
22
|
+
"import": {
|
|
23
|
+
"types": "./dist/constants.d.mts",
|
|
24
|
+
"default": "./dist/constants.mjs"
|
|
25
|
+
},
|
|
26
|
+
"require": {
|
|
27
|
+
"types": "./dist/constants.d.ts",
|
|
28
|
+
"default": "./dist/constants.js"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsup",
|
|
37
|
+
"dev": "tsup --watch",
|
|
38
|
+
"clean": "rimraf dist",
|
|
39
|
+
"test": "jest",
|
|
40
|
+
"verify:types": "node scripts/verify-package-types.js",
|
|
41
|
+
"prepack": "yarn build && yarn verify:types"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/OneKeyHQ/hardware-js-sdk.git",
|
|
49
|
+
"directory": "packages/hwk-desktop-noble-ble"
|
|
50
|
+
},
|
|
51
|
+
"keywords": [
|
|
52
|
+
"trezor",
|
|
53
|
+
"electron",
|
|
54
|
+
"ble",
|
|
55
|
+
"bluetooth",
|
|
56
|
+
"hardware-wallet",
|
|
57
|
+
"onekey",
|
|
58
|
+
"connector"
|
|
59
|
+
],
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@onekeyfe/hwk-adapter-core": "1.2.3-alpha.2",
|
|
62
|
+
"buffer": "^6.0.3"
|
|
63
|
+
},
|
|
64
|
+
"peerDependencies": {
|
|
65
|
+
"@stoprocent/noble": "*",
|
|
66
|
+
"electron": "*"
|
|
67
|
+
},
|
|
68
|
+
"peerDependenciesMeta": {
|
|
69
|
+
"@stoprocent/noble": {
|
|
70
|
+
"optional": true
|
|
71
|
+
},
|
|
72
|
+
"electron": {
|
|
73
|
+
"optional": true
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
"devDependencies": {
|
|
77
|
+
"rimraf": "^5.0.0",
|
|
78
|
+
"tsup": "^8.0.0",
|
|
79
|
+
"typescript": "5.1.6"
|
|
80
|
+
},
|
|
81
|
+
"gitHead": "8b790c78394debdd3d9999db2f6a56235efb7a18"
|
|
82
|
+
}
|