@ledgerhq/device-transport-kit-react-native-ble 0.0.0-try-to-fix-20250429171448 → 1.0.0
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/README.md +2 -5
- package/lib/cjs/api/model/Const.js +1 -1
- package/lib/cjs/api/model/Const.js.map +3 -3
- package/lib/cjs/api/model/Errors.js +1 -1
- package/lib/cjs/api/model/Errors.js.map +3 -3
- package/lib/cjs/api/transport/RNBleApduSender.js +1 -1
- package/lib/cjs/api/transport/RNBleApduSender.js.map +3 -3
- package/lib/cjs/api/transport/RNBleApduSender.test.js +1 -1
- package/lib/cjs/api/transport/RNBleApduSender.test.js.map +2 -2
- package/lib/cjs/api/transport/RNBleTransport.js +1 -1
- package/lib/cjs/api/transport/RNBleTransport.js.map +3 -3
- package/lib/cjs/api/transport/RNBleTransport.test.js +1 -1
- package/lib/cjs/api/transport/RNBleTransport.test.js.map +3 -3
- package/lib/cjs/package.json +17 -17
- package/lib/esm/api/model/Const.js +1 -1
- package/lib/esm/api/model/Const.js.map +3 -3
- package/lib/esm/api/model/Errors.js +1 -1
- package/lib/esm/api/model/Errors.js.map +3 -3
- package/lib/esm/api/transport/RNBleApduSender.js +1 -1
- package/lib/esm/api/transport/RNBleApduSender.js.map +3 -3
- package/lib/esm/api/transport/RNBleApduSender.test.js +1 -1
- package/lib/esm/api/transport/RNBleApduSender.test.js.map +2 -2
- package/lib/esm/api/transport/RNBleTransport.js +1 -1
- package/lib/esm/api/transport/RNBleTransport.js.map +3 -3
- package/lib/esm/api/transport/RNBleTransport.test.js +1 -1
- package/lib/esm/api/transport/RNBleTransport.test.js.map +3 -3
- package/lib/esm/package.json +17 -17
- package/lib/types/api/model/Const.d.ts +2 -1
- package/lib/types/api/model/Const.d.ts.map +1 -1
- package/lib/types/api/model/Errors.d.ts +21 -1
- package/lib/types/api/model/Errors.d.ts.map +1 -1
- package/lib/types/api/transport/RNBleApduSender.d.ts +5 -6
- package/lib/types/api/transport/RNBleApduSender.d.ts.map +1 -1
- package/lib/types/api/transport/RNBleTransport.d.ts +22 -71
- package/lib/types/api/transport/RNBleTransport.d.ts.map +1 -1
- package/lib/types/tsconfig.prod.tsbuildinfo +1 -1
- package/package.json +13 -13
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/api/transport/RNBleTransport.test.ts"],
|
|
4
|
-
"sourcesContent": ["import { type PermissionsAndroid, type Platform } from \"react-native\";\nimport { type PermissionStatus } from \"react-native/Libraries/PermissionsAndroid/PermissionsAndroid\";\nimport { type BleManager } from \"react-native-ble-plx\";\nimport {\n type ApduReceiverServiceFactory,\n type ApduSenderServiceFactory,\n BleDeviceInfos,\n DeviceConnectionStateMachine,\n type DeviceConnectionStateMachineParams,\n type DeviceModelDataSource,\n DeviceModelId,\n type DmkConfig,\n type LoggerPublisherService,\n TransportConnectedDevice,\n TransportDeviceModel,\n type TransportDiscoveredDevice,\n UnknownDeviceError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Left, Right } from \"purify-ts\";\nimport { firstValueFrom } from \"rxjs\";\nimport { beforeEach, expect, type Mock } from \"vitest\";\n\nimport { BleNotSupported } from \"@api/model/Errors\";\n\nimport { type RNBleApduSenderDependencies } from \"./RNBleApduSender\";\nimport { RNBleTransport, RNBleTransportFactory } from \"./RNBleTransport\";\n\nconst fakeLogger = {\n error: vi.fn(),\n info: vi.fn(),\n warn: vi.fn(),\n debug: vi.fn(),\n};\n\nvi.mock(\"react-native\", () => ({\n Platform: {},\n PermissionsAndroid: {},\n}));\n\nvi.mock(\"react-native-ble-plx\", () => ({\n BleManager: vi.fn(),\n}));\n\nconst expectAndroidSupportedResult = async (\n params: {\n version: number;\n permissions: Record<string, string>;\n requestPermissionResult: {\n \"android.permission.BLUETOOTH_CONNECT\": PermissionStatus;\n \"android.permission.BLUETOOTH_SCAN\": PermissionStatus;\n \"android.permission.ACCESS_FINE_LOCATION\": PermissionStatus;\n };\n accessFineLocationResult?: PermissionStatus;\n },\n expects: {\n isSupported: boolean;\n callRequestPermission: boolean;\n },\n) => {\n // given\n const platform = { OS: \"android\", Version: params.version };\n const permissionsAndroid = {\n request: vi.fn().mockImplementation((key: string) =>\n Promise.resolve(\n {\n ACCESS_FINE_LOCATION: params.accessFineLocationResult,\n }[key],\n ),\n ),\n PERMISSIONS: params.permissions,\n RESULTS: {\n GRANTED: \"granted\",\n },\n requestMultiple: vi\n .fn()\n .mockImplementation(() =>\n Promise.resolve(params.requestPermissionResult),\n ),\n };\n const transport = new RNBleTransport(\n \"DeviceModelDataSource\" as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n platform as Platform,\n permissionsAndroid as unknown as PermissionsAndroid,\n );\n // when\n await transport.requestPermission();\n const isSupported = transport.isSupported();\n // then\n if (expects.callRequestPermission) {\n expect(permissionsAndroid.request).toHaveBeenCalledWith(\n \"ACCESS_FINE_LOCATION\",\n );\n }\n expect(isSupported).toBe(expects.isSupported);\n};\n\ndescribe(\"RNBleTransportFactory\", () => {\n it(\"should return a RNBleTransport\", () => {\n const fakeArgs = {\n deviceModelDataSource:\n \"DeviceModelDataSource\" as unknown as DeviceModelDataSource,\n loggerServiceFactory: () =>\n fakeLogger as unknown as LoggerPublisherService,\n apduSenderServiceFactory:\n (() => {}) as unknown as ApduSenderServiceFactory,\n apduReceiverServiceFactory:\n (() => {}) as unknown as ApduReceiverServiceFactory,\n config: {} as DmkConfig,\n };\n // when\n const transport = RNBleTransportFactory(fakeArgs);\n // then\n expect(transport).toBeInstanceOf(RNBleTransport);\n });\n});\n\ndescribe(\"RNBleTransport\", () => {\n const fakePlaftorm = { OS: \"ios\" };\n const fakeDeviceModel = new TransportDeviceModel({\n id: DeviceModelId.FLEX,\n productName: \"Ledger Flex\",\n usbProductId: 0x70,\n bootloaderUsbProductId: 0x0007,\n usbOnly: false,\n memorySize: 1533 * 1024,\n masks: [0x33300000],\n });\n const getBluetoothServicesMock = vi.fn(() => [\"ledgerId\"]);\n const getBluetoothServicesInfosMock = vi.fn(() => ({\n ledgerId: new BleDeviceInfos(\n fakeDeviceModel,\n \"serviceUuid\",\n \"notifyUuid\",\n \"writeCmdUuid\",\n \"readCmdUuid\",\n ),\n }));\n const fakeDataSource = {\n getBluetoothServices: getBluetoothServicesMock,\n getBluetoothServicesInfos: getBluetoothServicesInfosMock,\n };\n\n beforeEach(() => {\n vi.clearAllMocks();\n });\n\n describe(\"getIdentifier\", () => {\n it(\"should return rnBleTransportIdentifier\", () => {\n // given\n const transport = new RNBleTransport(\n \"DeviceModelDataSource\" as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n );\n\n // when\n const identifier = transport.getIdentifier();\n\n // then\n expect(identifier).toStrictEqual(\"RN_BLE\");\n });\n });\n\n describe(\"isSupported\", () => {\n it(\"should return true if platform is ios\", async () => {\n // given\n const platform = { OS: \"ios\" };\n const transport = new RNBleTransport(\n \"DeviceModelDataSource\" as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n platform as Platform,\n );\n\n // when\n await transport.requestPermission();\n const isSupported = transport.isSupported();\n\n // then\n expect(isSupported).toBe(true);\n });\n\n it(\"should return true if platform is android and apiLevel < 31 with good permissions\", async () => {\n await expectAndroidSupportedResult(\n {\n version: 30,\n permissions: {\n ACCESS_FINE_LOCATION: \"ACCESS_FINE_LOCATION\",\n BLUETOOTH_SCAN: \"BLUETOOTH_SCAN\",\n BLUETOOTH_CONNECT: \"BLUETOOTH_CONNECT\",\n },\n requestPermissionResult: {\n \"android.permission.BLUETOOTH_CONNECT\": \"granted\",\n \"android.permission.BLUETOOTH_SCAN\": \"granted\",\n \"android.permission.ACCESS_FINE_LOCATION\": \"granted\",\n },\n },\n {\n isSupported: true,\n callRequestPermission: true,\n },\n );\n });\n\n it(\"should return true if platform is android and apiLevel >= 31 with good permissions\", async () => {\n await expectAndroidSupportedResult(\n {\n version: 31,\n permissions: {\n ACCESS_FINE_LOCATION: \"ACCESS_FINE_LOCATION\",\n BLUETOOTH_SCAN: \"BLUETOOTH_SCAN\",\n BLUETOOTH_CONNECT: \"BLUETOOTH_CONNECT\",\n },\n requestPermissionResult: {\n \"android.permission.BLUETOOTH_CONNECT\": \"granted\",\n \"android.permission.BLUETOOTH_SCAN\": \"granted\",\n \"android.permission.ACCESS_FINE_LOCATION\": \"granted\",\n },\n },\n {\n isSupported: true,\n callRequestPermission: false,\n },\n );\n });\n\n it(\"should return false if platform is android with bad permissions\", async () => {\n await expectAndroidSupportedResult(\n {\n version: 31,\n permissions: {\n ACCESS_FINE_LOCATION: \"\",\n BLUETOOTH_SCAN: \"\",\n BLUETOOTH_CONNECT: \"BLUETOOTH_CONNECT\",\n },\n requestPermissionResult: {\n \"android.permission.ACCESS_FINE_LOCATION\": \"denied\",\n \"android.permission.BLUETOOTH_CONNECT\": \"granted\",\n \"android.permission.BLUETOOTH_SCAN\": \"granted\",\n },\n },\n {\n isSupported: false,\n callRequestPermission: false,\n },\n );\n });\n\n it(\"should return false if platform is android and denied permissions\", async () => {\n await expectAndroidSupportedResult(\n {\n version: 31,\n permissions: {\n ACCESS_FINE_LOCATION: \"ACCESS_FINE_LOCATION\",\n BLUETOOTH_SCAN: \"BLUETOOTH_SCAN\",\n BLUETOOTH_CONNECT: \"BLUETOOTH_CONNECT\",\n },\n requestPermissionResult: {\n \"android.permission.BLUETOOTH_CONNECT\": \"denied\",\n \"android.permission.BLUETOOTH_SCAN\": \"denied\",\n \"android.permission.ACCESS_FINE_LOCATION\": \"denied\",\n },\n },\n {\n isSupported: false,\n callRequestPermission: false,\n },\n );\n });\n\n it(\"should return false if platform isn't android nor ios\", async () => {\n // given\n const transport = new RNBleTransport(\n \"DeviceModelDataSource\" as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n { OS: \"windows\" } as Platform,\n );\n\n // when\n await transport.requestPermission();\n const isSupported = transport.isSupported();\n\n // then\n expect(isSupported).toBe(false);\n });\n });\n\n describe(\"startDiscovering\", () => {\n it(\"should throw error if transport is not supported\", () => {\n // given\n const platform = { OS: \"windows\" };\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n platform as Platform,\n );\n\n try {\n // when\n transport.startDiscovering();\n } catch (e) {\n // then\n expect(e).toBeInstanceOf(BleNotSupported);\n }\n });\n\n it(\"should emit discovered known device\", () =>\n new Promise((done) => {\n // given\n const bleManager = {\n connectedDevices: vi.fn().mockResolvedValueOnce([\n {\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi\n .fn()\n .mockResolvedValueOnce({\n services: vi.fn().mockResolvedValue({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n id: \"id\",\n localName: \"name\",\n }),\n }),\n },\n ]),\n startDeviceScan: vi.fn(),\n stopDeviceScan: vi.fn(),\n onDeviceDisconnected: vi.fn(),\n } as unknown as BleManager;\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n () => bleManager,\n );\n\n // when\n const observable = transport.startDiscovering();\n\n // then\n const subscription = observable.subscribe({\n next: (discoveredDevice) => {\n expect(discoveredDevice).toStrictEqual({\n id: \"id\",\n name: \"name\",\n deviceModel: fakeDeviceModel,\n transport: \"RN_BLE\",\n rssi: 42,\n });\n subscription.unsubscribe();\n done(void 0);\n },\n error: (e) => {\n if (subscription && !subscription.closed) {\n subscription.unsubscribe();\n }\n throw e;\n },\n complete: () => {\n if (subscription && !subscription.closed) {\n subscription.unsubscribe();\n }\n throw new Error(\"complete should not be called\");\n },\n });\n }));\n\n it(\"should emit discovered new device\", () =>\n new Promise((done) => {\n // given\n let scanInterval: NodeJS.Timeout;\n\n const startScan = vi.fn((_uuids, _options, listener) => {\n scanInterval = setInterval(() => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n listener(null, {\n id: \"id\",\n localName: \"name\",\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n });\n }, 500);\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n listener(null, {\n id: \"43\",\n localName: \"name43\",\n serviceUUIDs: [\"notLedgerId\"],\n rssi: 43,\n });\n });\n\n const stopScan = vi.fn(() => {\n clearInterval(scanInterval);\n });\n\n const bleManager = {\n connectedDevices: vi.fn().mockResolvedValueOnce([]),\n startDeviceScan: startScan,\n stopDeviceScan: stopScan,\n onDeviceDisconnected: vi.fn(),\n } as unknown as BleManager;\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n () => bleManager,\n );\n\n // when\n const observable = transport.startDiscovering();\n\n // then\n const subscription = observable.subscribe({\n next: (discoveredDevice) => {\n expect(discoveredDevice).toStrictEqual({\n id: \"id\",\n name: \"name\",\n deviceModel: fakeDeviceModel,\n transport: \"RN_BLE\",\n rssi: 42,\n });\n subscription.unsubscribe();\n done(void 0);\n },\n error: (e) => {\n if (subscription && !subscription.closed) {\n subscription.unsubscribe();\n }\n throw e;\n },\n complete: () => {\n if (subscription && !subscription.closed) {\n subscription.unsubscribe();\n }\n throw new Error(\"complete should not be called\");\n },\n });\n }));\n\n it(\"should emit both known and new device\", () =>\n new Promise((done) => {\n // given\n let scanInterval: NodeJS.Timeout;\n const startScan = vi.fn((_uuids, _options, listener) => {\n scanInterval = setInterval(() => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n listener(null, {\n id: \"newDeviceId\",\n localName: \"newDeviceName\",\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n });\n }, 500);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n listener(null, {\n id: \"43\",\n localName: \"name43\",\n serviceUUIDs: [\"notLedgerId\"],\n rssi: 43,\n });\n });\n\n const stopScan = vi.fn(() => {\n clearInterval(scanInterval);\n });\n\n const fakeConnectedDevices = vi.fn().mockResolvedValueOnce([\n {\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi\n .fn()\n .mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"knownDeviceId\",\n localName: \"knownDeviceName\",\n }),\n }),\n },\n ]);\n\n const bleManager = {\n connectedDevices: fakeConnectedDevices,\n startDeviceScan: startScan,\n stopDeviceScan: stopScan,\n onDeviceDisconnected: vi.fn(),\n } as unknown as BleManager;\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n () => bleManager,\n );\n\n // when\n const obs = transport.startDiscovering();\n const discoveredDevices: Record<string, TransportDiscoveredDevice> = {};\n\n // then\n const subscription = obs.subscribe({\n next: (device) => {\n discoveredDevices[device.id] = device;\n if (Object.values(discoveredDevices).length === 2) {\n subscription.unsubscribe();\n expect(Object.values(discoveredDevices)).toStrictEqual([\n {\n id: \"knownDeviceId\",\n name: \"knownDeviceName\",\n deviceModel: fakeDeviceModel,\n transport: \"RN_BLE\",\n rssi: 64,\n },\n {\n id: \"newDeviceId\",\n name: \"newDeviceName\",\n deviceModel: fakeDeviceModel,\n transport: \"RN_BLE\",\n rssi: 42,\n },\n ]);\n done(void 0);\n }\n },\n });\n }));\n });\n\n describe(\"stopDiscovering\", () => {\n it(\"should call ble manager stop scan on stop discovering\", () => {\n // given\n const fakeStopDeviceScan = vi.fn();\n const bleManager = {\n connectedDevices: vi.fn().mockResolvedValueOnce([]),\n startDeviceScan: vi.fn(),\n stopDeviceScan: fakeStopDeviceScan,\n onDeviceDisconnected: vi.fn(),\n } as unknown as BleManager;\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n () => bleManager,\n );\n\n // when\n transport.stopDiscovering();\n\n // then\n expect(fakeStopDeviceScan).toHaveBeenCalled();\n });\n\n it(\"should call ble manager stop scan when unsubscribe startDiscovering obs\", () => {\n // given\n let scanInterval: NodeJS.Timeout | undefined;\n\n const startScan = vi.fn((_uuids, _options, listener) => {\n scanInterval = setInterval(() => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n listener(null, {\n id: \"id\",\n localName: \"name\",\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n });\n }, 500);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n listener(null, {\n id: \"43\",\n localName: \"name43\",\n serviceUUIDs: [\"notLedgerId\"],\n rssi: 43,\n });\n });\n\n const stopScan = vi.fn(() => {\n clearInterval(scanInterval);\n scanInterval = undefined;\n });\n\n const bleManager = {\n connectedDevices: vi.fn().mockResolvedValueOnce([]),\n startDeviceScan: startScan,\n stopDeviceScan: stopScan,\n onDeviceDisconnected: vi.fn(),\n } as unknown as BleManager;\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n () => bleManager,\n );\n\n // when\n transport.startDiscovering().subscribe().unsubscribe();\n\n // then\n expect(startScan).toHaveBeenCalled();\n expect(stopScan).toHaveBeenCalled();\n });\n });\n\n describe(\"listenToAvailableDevices\", () => {\n it(\"should call startScan and connectedDevices from ble manager\", () =>\n new Promise((done) => {\n // given\n let scanInterval: NodeJS.Timeout | undefined;\n\n const startScan = vi.fn((_uuids, _options, listener) => {\n scanInterval = setInterval(() => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n listener(null, {\n id: \"id\",\n localName: \"name\",\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n });\n }, 500);\n // eslint-disable-next-line @typescript-eslint/no-unsafe-call\n listener(null, {\n id: \"43\",\n localName: \"name43\",\n serviceUUIDs: [\"notLedgerId\"],\n rssi: 43,\n });\n });\n const stopScan = vi.fn(() => {\n clearInterval(scanInterval);\n scanInterval = undefined;\n });\n const fakeConnectedDevices = vi.fn().mockResolvedValueOnce([\n {\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi\n .fn()\n .mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"knownDeviceId\",\n localName: \"knownDeviceName\",\n }),\n }),\n },\n ]);\n const bleManager = {\n connectedDevices: fakeConnectedDevices,\n startDeviceScan: startScan,\n stopDeviceScan: stopScan,\n onDeviceDisconnected: vi.fn(),\n isDeviceConnected: vi.fn(),\n } as unknown as BleManager;\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n () => bleManager,\n );\n\n // when\n const sub = transport.listenToAvailableDevices().subscribe({\n next: (devices) => {\n if (devices.length === 2) {\n // then\n expect(devices).toEqual([\n {\n id: \"knownDeviceId\",\n name: \"knownDeviceName\",\n deviceModel: fakeDeviceModel,\n transport: \"RN_BLE\",\n rssi: 64,\n },\n {\n id: \"id\",\n name: \"name\",\n deviceModel: fakeDeviceModel,\n transport: \"RN_BLE\",\n rssi: 42,\n },\n ]);\n sub.unsubscribe();\n done(void 0);\n }\n },\n });\n }));\n });\n\n describe(\"connect\", () => {\n let fakeConnectedDevices: Mock;\n\n beforeEach(() => {\n fakeConnectedDevices = vi.fn().mockResolvedValueOnce([\n {\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi\n .fn()\n .mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"deviceId\",\n localName: \"knownDeviceName\",\n }),\n }),\n },\n ]);\n });\n\n it(\"should throw an error if device id is unknown\", async () => {\n // given\n const bleManager = {\n connectedDevices: vi.fn(),\n startDeviceScan: vi.fn(),\n stopDeviceScan: vi.fn(),\n onDeviceDisconnected: vi.fn(),\n isDeviceConnected: vi.fn(),\n } as unknown as BleManager;\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n () => bleManager,\n );\n\n // when\n const result = await transport.connect({\n deviceId: \"42\",\n onDisconnect: vi.fn(),\n });\n\n // then\n expect(result).toEqual(Left(new UnknownDeviceError(`Unknown device 42`)));\n });\n\n it(\"should connect to a discovered device with correct MTU and discover services and setup apdu sender\", async () => {\n // given\n const bleManager = {\n connectedDevices: fakeConnectedDevices,\n startDeviceScan: vi.fn(),\n stopDeviceScan: vi.fn(),\n onDeviceDisconnected: vi.fn(),\n isDeviceConnected: vi.fn(),\n monitorCharacteristicForDevice: vi.fn(),\n writeCharacteristicWithoutResponseForDevice: vi.fn(),\n connectToDevice: vi.fn().mockResolvedValueOnce({\n id: \"deviceId\",\n rssi: 64,\n }),\n discoverAllServicesAndCharacteristicsForDevice: vi.fn(),\n } as unknown as BleManager;\n\n const fakeSetupConnection = vi.fn();\n const deviceConnectionStateMachineFactory = vi.fn().mockReturnValue({\n sendApdu: vi.fn(),\n });\n const deviceApduSenderFactory = vi.fn().mockReturnValue({\n setupConnection: fakeSetupConnection,\n });\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n () => bleManager,\n deviceConnectionStateMachineFactory,\n deviceApduSenderFactory,\n );\n\n // when\n const device = await firstValueFrom(transport.startDiscovering());\n const result = await transport.connect({\n deviceId: device.id,\n onDisconnect: vi.fn(),\n });\n\n // then\n expect(result.isRight()).toBe(true);\n expect(bleManager.connectToDevice).toHaveBeenCalledWith(\"deviceId\", {\n requestMTU: 156,\n });\n expect(\n bleManager.discoverAllServicesAndCharacteristicsForDevice,\n ).toHaveBeenCalledWith(\"deviceId\");\n expect(fakeSetupConnection).toHaveBeenCalled();\n });\n\n it(\"should return a connected device which calls state machine sendApdu\", async () => {\n // given\n const bleManager = {\n connectedDevices: fakeConnectedDevices,\n startDeviceScan: vi.fn(),\n stopDeviceScan: vi.fn(),\n onDeviceDisconnected: vi.fn(),\n isDeviceConnected: vi.fn(),\n monitorCharacteristicForDevice: vi.fn(),\n writeCharacteristicWithoutResponseForDevice: vi.fn(),\n connectToDevice: vi.fn().mockResolvedValueOnce({\n id: \"deviceId\",\n rssi: 64,\n }),\n discoverAllServicesAndCharacteristicsForDevice: vi.fn(),\n } as unknown as BleManager;\n\n const fakeSendApdu = vi.fn();\n const deviceConnectionStateMachineFactory = vi.fn().mockReturnValue({\n sendApdu: fakeSendApdu,\n });\n const deviceApduSenderFactory = vi.fn().mockReturnValue({\n setupConnection: vi.fn(),\n });\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n () => bleManager,\n deviceConnectionStateMachineFactory,\n deviceApduSenderFactory,\n );\n\n // when\n const device = await firstValueFrom(transport.startDiscovering());\n const result = await transport.connect({\n deviceId: device.id,\n onDisconnect: vi.fn(),\n });\n\n const connectedDevice = result.extract() as TransportConnectedDevice;\n connectedDevice.sendApdu(Uint8Array.from([0x43, 0x32]));\n // then\n expect(result).toEqual(\n Right(\n new TransportConnectedDevice({\n id: \"deviceId\",\n deviceModel: fakeDeviceModel,\n type: \"BLE\",\n transport: \"RN_BLE\",\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n sendApdu: expect.any(Function),\n }),\n ),\n );\n expect(fakeSendApdu).toHaveBeenCalledWith(Uint8Array.from([0x43, 0x32]));\n });\n });\n\n describe(\"disconnect\", () => {\n let fakeConnectedDevices: Mock;\n\n beforeEach(() => {\n fakeConnectedDevices = vi.fn().mockResolvedValueOnce([\n {\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi\n .fn()\n .mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"deviceId\",\n localName: \"knownDeviceName\",\n }),\n }),\n },\n ]);\n });\n\n it(\"should disconnect gracefully\", async () => {\n const onDeviceDisconnected = vi\n .fn()\n .mockImplementation((_id, callback) => {\n callback(null, {\n deviceId: \"deviceId\",\n connect: vi.fn().mockResolvedValue({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"deviceId\",\n localName: \"knownDeviceName\",\n }),\n discoverAllServicesAndCharacteristics: vi\n .fn()\n .mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"deviceId\",\n localName: \"knownDeviceName\",\n }),\n });\n return { remove: vi.fn() };\n });\n // given\n const bleManager = {\n connectedDevices: fakeConnectedDevices,\n startDeviceScan: vi.fn(),\n stopDeviceScan: vi.fn(),\n onDeviceDisconnected: onDeviceDisconnected,\n isDeviceConnected: vi.fn(),\n monitorCharacteristicForDevice: vi.fn(),\n writeCharacteristicWithoutResponseForDevice: vi.fn(),\n connectToDevice: vi.fn().mockResolvedValueOnce({\n id: \"deviceId\",\n rssi: 64,\n }),\n discoverAllServicesAndCharacteristicsForDevice: vi.fn(),\n } as unknown as BleManager;\n\n const fakeCloseConnection = vi.fn();\n\n const deviceConnectionStateMachineFactory = (\n _args: DeviceConnectionStateMachineParams<RNBleApduSenderDependencies>,\n ) => {\n return new DeviceConnectionStateMachine({\n deviceId: \"deviceId\",\n deviceApduSender: _args.deviceApduSender,\n timeoutDuration: 1000,\n onTerminated: _args.onTerminated,\n });\n };\n\n const deviceApduSenderFactory = vi.fn().mockReturnValue({\n setupConnection: vi.fn(),\n closeConnection: fakeCloseConnection,\n });\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n () => bleManager,\n deviceConnectionStateMachineFactory,\n deviceApduSenderFactory,\n );\n\n const fakeOnDisconnect = vi.fn();\n\n // when\n const device = await firstValueFrom(transport.startDiscovering());\n const result = await transport.connect({\n deviceId: device.id,\n onDisconnect: fakeOnDisconnect,\n });\n\n const res = await transport.disconnect({\n connectedDevice: result.extract() as TransportConnectedDevice,\n });\n\n // then\n expect(res).toEqual(Right(undefined));\n expect(fakeOnDisconnect).toHaveBeenCalled();\n expect(fakeCloseConnection).toHaveBeenCalled();\n });\n\n it(\"should handle error while disconnecting\", async () => {\n const onDeviceDisconnected = vi\n .fn()\n .mockImplementation((_id, callback) => {\n callback(new Error(\"yolo\"), null);\n return { remove: vi.fn() };\n });\n // given\n const bleManager = {\n connectedDevices: fakeConnectedDevices,\n startDeviceScan: vi.fn(),\n stopDeviceScan: vi.fn(),\n onDeviceDisconnected: onDeviceDisconnected,\n isDeviceConnected: vi.fn(),\n monitorCharacteristicForDevice: vi.fn(),\n writeCharacteristicWithoutResponseForDevice: vi.fn(),\n connectToDevice: vi.fn().mockResolvedValueOnce({\n id: \"deviceId\",\n rssi: 64,\n }),\n discoverAllServicesAndCharacteristicsForDevice: vi.fn(),\n } as unknown as BleManager;\n\n const fakeCloseConnection = vi.fn();\n\n const deviceConnectionStateMachineFactory = (\n _args: DeviceConnectionStateMachineParams<RNBleApduSenderDependencies>,\n ) => {\n return new DeviceConnectionStateMachine({\n deviceId: \"deviceId\",\n deviceApduSender: _args.deviceApduSender,\n timeoutDuration: 1000,\n onTerminated: _args.onTerminated,\n });\n };\n\n const deviceApduSenderFactory = vi.fn().mockReturnValue({\n setupConnection: vi.fn(),\n closeConnection: fakeCloseConnection,\n });\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n () => bleManager,\n deviceConnectionStateMachineFactory,\n deviceApduSenderFactory,\n );\n\n const fakeOnDisconnect = vi.fn();\n\n // when\n const device = await firstValueFrom(transport.startDiscovering());\n const result = await transport.connect({\n deviceId: device.id,\n onDisconnect: fakeOnDisconnect,\n });\n\n const res = await transport.disconnect({\n connectedDevice: result.extract() as TransportConnectedDevice,\n });\n\n // then\n expect(res).toEqual(Right(undefined));\n expect(fakeOnDisconnect).toHaveBeenCalled();\n });\n });\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["import_device_management_kit", "import_purify_ts", "import_rxjs", "import_vitest", "import_Errors", "import_RNBleTransport", "fakeLogger", "expectAndroidSupportedResult", "params", "expects", "platform", "permissionsAndroid", "key", "transport", "isSupported", "fakePlaftorm", "fakeDeviceModel", "getBluetoothServicesMock", "getBluetoothServicesInfosMock", "fakeDataSource", "
|
|
4
|
+
"sourcesContent": ["/* eslint @typescript-eslint/consistent-type-imports: off */\nimport { type PermissionsAndroid, type Platform } from \"react-native\";\nimport { type PermissionStatus } from \"react-native/Libraries/PermissionsAndroid/PermissionsAndroid\";\nimport { BleManager, type Device, State } from \"react-native-ble-plx\";\nimport {\n type ApduReceiverServiceFactory,\n type ApduSenderServiceFactory,\n BleDeviceInfos,\n DeviceConnectionStateMachine,\n type DeviceConnectionStateMachineParams,\n type DeviceModelDataSource,\n DeviceModelId,\n type DmkConfig,\n type LoggerPublisherService,\n OpeningConnectionError,\n TransportConnectedDevice,\n TransportDeviceModel,\n type TransportDiscoveredDevice,\n} from \"@ledgerhq/device-management-kit\";\nimport { Left, Right } from \"purify-ts\";\nimport { lastValueFrom, Subscription, take } from \"rxjs\";\nimport { beforeEach, expect, type Mock } from \"vitest\";\n\nimport { BleNotSupported } from \"@api/model/Errors\";\n\nimport { type RNBleApduSenderDependencies } from \"./RNBleApduSender\";\nimport { RNBleTransport, RNBleTransportFactory } from \"./RNBleTransport\";\n\nconst fakeLogger = {\n error: vi.fn(),\n info: vi.fn(),\n warn: vi.fn(),\n debug: vi.fn(),\n};\n\nvi.mock(\"react-native\", () => ({\n Platform: {},\n PermissionsAndroid: {},\n}));\n\nvi.mock(\"react-native-ble-plx\", () => ({\n Device: vi.fn(),\n State: {\n PoweredOn: \"PoweredOn\",\n Unknown: \"Unknown\",\n },\n BleError: vi.fn(),\n BleManager: vi.fn().mockReturnValue({\n onStateChange: vi.fn(),\n startDeviceScan: vi.fn(),\n stopDeviceScan: vi.fn(),\n connectToDevice: vi.fn(),\n disconnectFromDevice: vi.fn(),\n cancelDeviceConnection: vi.fn(),\n connectedDevices: vi.fn(),\n monitorCharacteristicForDevice: vi.fn(),\n writeCharacteristicWithoutResponseForDevice: vi.fn(),\n discoverAllServicesAndCharacteristicsForDevice: vi.fn(),\n onDeviceDisconnected: vi.fn(),\n isDeviceConnected: vi.fn(),\n }),\n}));\n\nconst expectAndroidSupportedResult = async (\n params: {\n version: number;\n permissions: Record<string, string>;\n requestPermissionResult: {\n \"android.permission.BLUETOOTH_CONNECT\": PermissionStatus;\n \"android.permission.BLUETOOTH_SCAN\": PermissionStatus;\n \"android.permission.ACCESS_FINE_LOCATION\": PermissionStatus;\n };\n accessFineLocationResult?: PermissionStatus;\n },\n expects: {\n isSupported: boolean;\n callRequestPermission: boolean;\n },\n) => {\n // given\n const platform = { OS: \"android\", Version: params.version };\n const permissionsAndroid = {\n request: vi.fn().mockImplementation((key: string) =>\n Promise.resolve(\n {\n ACCESS_FINE_LOCATION: params.accessFineLocationResult,\n }[key],\n ),\n ),\n PERMISSIONS: params.permissions,\n RESULTS: {\n GRANTED: \"granted\",\n },\n requestMultiple: vi\n .fn()\n .mockImplementation(() =>\n Promise.resolve(params.requestPermissionResult),\n ),\n };\n const transport = new RNBleTransport(\n \"DeviceModelDataSource\" as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n new BleManager(),\n platform as Platform,\n permissionsAndroid as unknown as PermissionsAndroid,\n );\n // when\n await transport.requestPermission();\n const isSupported = transport.isSupported();\n // then\n if (expects.callRequestPermission) {\n expect(permissionsAndroid.request).toHaveBeenCalledWith(\n \"ACCESS_FINE_LOCATION\",\n );\n }\n expect(isSupported).toBe(expects.isSupported);\n};\n\ndescribe(\"RNBleTransportFactory\", () => {\n it(\"should return a RNBleTransport\", () => {\n const fakeArgs = {\n deviceModelDataSource:\n \"DeviceModelDataSource\" as unknown as DeviceModelDataSource,\n loggerServiceFactory: () =>\n fakeLogger as unknown as LoggerPublisherService,\n apduSenderServiceFactory:\n (() => {}) as unknown as ApduSenderServiceFactory,\n apduReceiverServiceFactory:\n (() => {}) as unknown as ApduReceiverServiceFactory,\n config: {} as DmkConfig,\n };\n // when\n const transport = RNBleTransportFactory(fakeArgs);\n // then\n expect(transport).toBeInstanceOf(RNBleTransport);\n });\n});\n\ndescribe(\"RNBleTransport\", () => {\n const fakePlaftorm = { OS: \"ios\" };\n const fakeDeviceModel = new TransportDeviceModel({\n id: DeviceModelId.FLEX,\n productName: \"Ledger Flex\",\n usbProductId: 0x70,\n bootloaderUsbProductId: 0x0007,\n usbOnly: false,\n memorySize: 1533 * 1024,\n blockSize: 32,\n masks: [0x33300000],\n });\n const getBluetoothServicesMock = vi.fn(() => [\"ledgerId\"]);\n const getBluetoothServicesInfosMock = vi.fn(() => ({\n ledgerId: new BleDeviceInfos(\n fakeDeviceModel,\n \"serviceUuid\",\n \"notifyUuid\",\n \"writeCmdUuid\",\n \"readCmdUuid\",\n ),\n }));\n const fakeDataSource = {\n getBluetoothServices: getBluetoothServicesMock,\n getBluetoothServicesInfos: getBluetoothServicesInfosMock,\n };\n\n let subscription: Subscription | undefined;\n\n beforeEach(() => {\n vi.clearAllMocks();\n });\n\n afterEach(() => {\n if (subscription) {\n subscription.unsubscribe();\n }\n });\n\n describe(\"getIdentifier\", () => {\n it(\"should return rnBleTransportIdentifier\", () => {\n // given\n const bleManager = new BleManager();\n const transport = new RNBleTransport(\n \"DeviceModelDataSource\" as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n );\n\n // when\n const identifier = transport.getIdentifier();\n\n // then\n expect(identifier).toStrictEqual(\"RN_BLE\");\n });\n });\n\n describe(\"isSupported\", () => {\n it(\"should return true if platform is ios\", async () => {\n // given\n const platform = { OS: \"ios\" };\n const bleManager = new BleManager();\n const transport = new RNBleTransport(\n \"DeviceModelDataSource\" as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n platform as Platform,\n );\n\n // when\n await transport.requestPermission();\n const isSupported = transport.isSupported();\n\n // then\n expect(isSupported).toBe(true);\n });\n\n it(\"should return true if platform is android and apiLevel < 31 with good permissions\", async () => {\n await expectAndroidSupportedResult(\n {\n version: 30,\n permissions: {\n ACCESS_FINE_LOCATION: \"ACCESS_FINE_LOCATION\",\n BLUETOOTH_SCAN: \"BLUETOOTH_SCAN\",\n BLUETOOTH_CONNECT: \"BLUETOOTH_CONNECT\",\n },\n requestPermissionResult: {\n \"android.permission.BLUETOOTH_CONNECT\": \"granted\",\n \"android.permission.BLUETOOTH_SCAN\": \"granted\",\n \"android.permission.ACCESS_FINE_LOCATION\": \"granted\",\n },\n },\n {\n isSupported: true,\n callRequestPermission: true,\n },\n );\n });\n\n it(\"should return true if platform is android and apiLevel >= 31 with good permissions\", async () => {\n await expectAndroidSupportedResult(\n {\n version: 31,\n permissions: {\n ACCESS_FINE_LOCATION: \"ACCESS_FINE_LOCATION\",\n BLUETOOTH_SCAN: \"BLUETOOTH_SCAN\",\n BLUETOOTH_CONNECT: \"BLUETOOTH_CONNECT\",\n },\n requestPermissionResult: {\n \"android.permission.BLUETOOTH_CONNECT\": \"granted\",\n \"android.permission.BLUETOOTH_SCAN\": \"granted\",\n \"android.permission.ACCESS_FINE_LOCATION\": \"granted\",\n },\n },\n {\n isSupported: true,\n callRequestPermission: false,\n },\n );\n });\n\n it(\"should return false if platform is android with bad permissions\", async () => {\n await expectAndroidSupportedResult(\n {\n version: 31,\n permissions: {\n ACCESS_FINE_LOCATION: \"\",\n BLUETOOTH_SCAN: \"\",\n BLUETOOTH_CONNECT: \"BLUETOOTH_CONNECT\",\n },\n requestPermissionResult: {\n \"android.permission.ACCESS_FINE_LOCATION\": \"denied\",\n \"android.permission.BLUETOOTH_CONNECT\": \"granted\",\n \"android.permission.BLUETOOTH_SCAN\": \"granted\",\n },\n },\n {\n isSupported: false,\n callRequestPermission: false,\n },\n );\n });\n\n it(\"should return false if platform is android and denied permissions\", async () => {\n await expectAndroidSupportedResult(\n {\n version: 31,\n permissions: {\n ACCESS_FINE_LOCATION: \"ACCESS_FINE_LOCATION\",\n BLUETOOTH_SCAN: \"BLUETOOTH_SCAN\",\n BLUETOOTH_CONNECT: \"BLUETOOTH_CONNECT\",\n },\n requestPermissionResult: {\n \"android.permission.BLUETOOTH_CONNECT\": \"denied\",\n \"android.permission.BLUETOOTH_SCAN\": \"denied\",\n \"android.permission.ACCESS_FINE_LOCATION\": \"denied\",\n },\n },\n {\n isSupported: false,\n callRequestPermission: false,\n },\n );\n });\n\n it(\"should return false if platform isn't android nor ios\", async () => {\n // given\n const bleManager = new BleManager();\n const transport = new RNBleTransport(\n \"DeviceModelDataSource\" as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n { OS: \"windows\" } as Platform,\n );\n\n // when\n await transport.requestPermission();\n const isSupported = transport.isSupported();\n\n // then\n expect(isSupported).toBe(false);\n });\n });\n\n // startDiscovering is not used / implemented anymore and just returns a from([])\n describe(\"startDiscovering\", () => {\n it(\"should throw error if transport is not supported\", () => {\n // given\n const platform = { OS: \"windows\" };\n const bleManager = new BleManager();\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n platform as Platform,\n );\n\n try {\n // when\n transport.startDiscovering();\n } catch (e) {\n // then\n expect(e).toBeInstanceOf(BleNotSupported);\n }\n });\n\n it(\"should emit an empty array\", () =>\n new Promise((done) => {\n // given\n const bleManager = new BleManager();\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n );\n\n // when\n const observable = transport.startDiscovering();\n\n // then\n subscription = observable.subscribe({\n next: (discoveredDevice) => {\n expect(discoveredDevice).toStrictEqual([]);\n done(undefined);\n },\n error: (e) => {\n throw e;\n },\n complete: () => {\n // Will complete as we use from([])\n done(undefined);\n },\n });\n }));\n\n it.skip(\"should emit discovered new device\", () =>\n new Promise((done) => {\n // given\n let scanInterval: NodeJS.Timeout | null = null;\n\n const bleManager = new BleManager();\n const startScan = vi\n .fn()\n .mockImplementation((_uuids, _options, listener) => {\n scanInterval = setInterval(() => {\n listener(null, {\n id: \"id\",\n localName: \"name\",\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n });\n }, 500);\n\n listener(null, {\n id: \"43\",\n localName: \"name43\",\n serviceUUIDs: [\"notLedgerId\"],\n rssi: 43,\n });\n\n return Promise.resolve();\n });\n\n const stopScan = vi.fn().mockImplementation(() => {\n if (scanInterval) {\n clearInterval(scanInterval);\n scanInterval = null;\n }\n return Promise.resolve();\n });\n\n vi.spyOn(bleManager, \"connectedDevices\").mockResolvedValueOnce([]);\n vi.spyOn(bleManager, \"startDeviceScan\").mockImplementation(startScan);\n vi.spyOn(bleManager, \"stopDeviceScan\").mockImplementation(stopScan);\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n );\n\n // when\n const observable = transport.startDiscovering();\n\n // then\n subscription = observable.subscribe({\n next: (discoveredDevice) => {\n expect(discoveredDevice).toStrictEqual([]);\n done(undefined);\n },\n error: (e) => {\n throw e;\n },\n complete: () => {\n throw new Error(\"complete should not be called\");\n },\n });\n }));\n\n it.skip(\"should emit both known and new device\", () =>\n new Promise((done) => {\n // given\n let scanInterval: NodeJS.Timeout | null = null;\n\n const bleManager = new BleManager();\n const mockDevice = {\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi\n .fn()\n .mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"knownDeviceId\",\n localName: \"knownDeviceName\",\n }),\n }),\n } as unknown as Device;\n\n const startScan = vi\n .fn()\n .mockImplementation((_uuids, _options, listener) => {\n scanInterval = setInterval(() => {\n listener(null, {\n id: \"newDeviceId\",\n localName: \"newDeviceName\",\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n } as unknown as Device);\n }, 500);\n\n listener(null, {\n id: \"43\",\n localName: \"name43\",\n serviceUUIDs: [\"notLedgerId\"],\n rssi: 43,\n } as unknown as Device);\n\n return Promise.resolve();\n });\n\n const stopScan = vi.fn().mockImplementation(() => {\n if (scanInterval) {\n clearInterval(scanInterval);\n scanInterval = null;\n }\n return Promise.resolve();\n });\n\n vi.spyOn(bleManager, \"connectedDevices\").mockResolvedValueOnce([\n mockDevice,\n ]);\n vi.spyOn(bleManager, \"startDeviceScan\").mockImplementation(startScan);\n vi.spyOn(bleManager, \"stopDeviceScan\").mockImplementation(stopScan);\n vi.spyOn(bleManager, \"onDeviceDisconnected\").mockImplementation(\n vi.fn(),\n );\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n );\n\n // when\n const obs = transport.startDiscovering();\n const discoveredDevices: Record<string, TransportDiscoveredDevice> = {};\n\n // then\n subscription = obs.subscribe({\n next: (device) => {\n discoveredDevices[device.id] = device;\n if (Object.values(discoveredDevices).length === 2) {\n expect(Object.values(discoveredDevices)).toStrictEqual([\n {\n id: \"knownDeviceId\",\n name: \"knownDeviceName\",\n deviceModel: fakeDeviceModel,\n transport: \"RN_BLE\",\n rssi: 64,\n },\n {\n id: \"newDeviceId\",\n name: \"newDeviceName\",\n deviceModel: fakeDeviceModel,\n transport: \"RN_BLE\",\n rssi: 42,\n },\n ]);\n done(undefined);\n }\n },\n });\n }));\n });\n\n describe(\"stopDiscovering\", () => {\n it(\"should call ble manager stop scan on stop discovering\", () => {\n // given\n const bleManager = new BleManager();\n const stopDeviceScan = vi.fn();\n vi.spyOn(bleManager, \"connectedDevices\").mockResolvedValueOnce([]);\n vi.spyOn(bleManager, \"stopDeviceScan\").mockImplementation(stopDeviceScan);\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n );\n\n // when\n transport.stopDiscovering();\n\n // then\n expect(stopDeviceScan).toHaveBeenCalled();\n });\n\n it.skip(\"should call ble manager stop scan when unsubscribe startDiscovering obs\", () => {\n // given\n let scanInterval: NodeJS.Timeout | null = null;\n\n const bleManager = new BleManager();\n const startScan = vi\n .fn()\n .mockImplementation((_uuids, _options, listener) => {\n scanInterval = setInterval(() => {\n listener(null, {\n id: \"id\",\n localName: \"name\",\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n });\n }, 500);\n listener(null, {\n id: \"43\",\n localName: \"name43\",\n serviceUUIDs: [\"notLedgerId\"],\n rssi: 43,\n });\n\n return Promise.resolve();\n });\n\n const stopScan = vi.fn().mockImplementation(() => {\n if (scanInterval) {\n clearInterval(scanInterval);\n scanInterval = null;\n }\n return Promise.resolve();\n });\n\n vi.spyOn(bleManager, \"connectedDevices\").mockResolvedValueOnce([]);\n vi.spyOn(bleManager, \"startDeviceScan\").mockImplementation(startScan);\n vi.spyOn(bleManager, \"stopDeviceScan\").mockImplementation(stopScan);\n vi.spyOn(bleManager, \"onDeviceDisconnected\").mockImplementation(vi.fn());\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n );\n\n // when\n transport.startDiscovering().subscribe().unsubscribe();\n\n // then\n expect(startScan).toHaveBeenCalled();\n expect(stopScan).toHaveBeenCalled();\n });\n });\n\n describe(\"listenToAvailableDevices\", () => {\n it(\"should call startScan and connectedDevices from ble manager\", () =>\n new Promise((done) => {\n // given\n let scanInterval: NodeJS.Timeout | null = null;\n\n const bleManager = new BleManager();\n const mockDevice = {\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi\n .fn()\n .mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"knownDeviceId\",\n localName: \"knownDeviceName\",\n }),\n }),\n } as unknown as Device;\n\n const startScan = vi\n .fn()\n .mockImplementation((_uuids, _options, listener) => {\n scanInterval = setInterval(() => {\n listener(null, {\n id: \"id\",\n localName: \"name\",\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n });\n }, 10);\n\n listener(null, {\n id: \"43\",\n localName: \"name43\",\n serviceUUIDs: [\"notLedgerId\"],\n rssi: 43,\n });\n });\n\n const stopScan = vi.fn().mockImplementation(() => {\n if (scanInterval) {\n clearInterval(scanInterval);\n scanInterval = null;\n }\n });\n\n vi.spyOn(bleManager, \"connectedDevices\").mockResolvedValueOnce([\n mockDevice,\n ]);\n vi.spyOn(bleManager, \"startDeviceScan\").mockImplementation(startScan);\n vi.spyOn(bleManager, \"stopDeviceScan\").mockImplementation(stopScan);\n vi.spyOn(bleManager, \"onDeviceDisconnected\").mockImplementation(\n vi.fn(),\n );\n vi.spyOn(bleManager, \"isDeviceConnected\").mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"onStateChange\").mockImplementation(\n (listener: (state: State) => void) => {\n listener(State.PoweredOn);\n return {\n remove: vi.fn(),\n };\n },\n );\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n );\n\n // when\n subscription = transport.listenToAvailableDevices().subscribe({\n next: (devices) => {\n if (devices.length === 1) {\n // then\n expect(devices).toEqual([\n {\n id: \"id\",\n name: \"name\",\n deviceModel: fakeDeviceModel,\n transport: \"RN_BLE\",\n rssi: 42,\n },\n ]);\n done(undefined);\n }\n },\n });\n }));\n });\n\n describe(\"connect\", () => {\n let fakeConnectedDevices: Mock;\n\n beforeEach(() => {\n fakeConnectedDevices = vi.fn().mockResolvedValueOnce([\n {\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi\n .fn()\n .mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"deviceId\",\n localName: \"knownDeviceName\",\n }),\n }),\n },\n ]);\n });\n\n it(\"should throw an error if device id is unknown\", async () => {\n // given\n const bleManager = new BleManager();\n\n vi.spyOn(bleManager, \"connectedDevices\").mockImplementation(\n fakeConnectedDevices,\n );\n\n vi.spyOn(\n bleManager,\n \"discoverAllServicesAndCharacteristicsForDevice\",\n ).mockRejectedValueOnce(\n new Error(\"discoverAllServicesAndCharacteristicsForDevice error\"),\n );\n\n const deviceApduSenderFactory = vi.fn().mockReturnValue({\n setupConnection: vi.fn().mockResolvedValue(undefined),\n });\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n vi.fn(),\n deviceApduSenderFactory,\n );\n\n // when\n const result = await transport.connect({\n // @ts-expect-error test case\n deviceId: null,\n onDisconnect: vi.fn(),\n });\n\n // then\n expect(result).toEqual(\n Left(\n new OpeningConnectionError(\n `discoverAllServicesAndCharacteristicsForDevice error`,\n ),\n ),\n );\n });\n\n it(\"should connect to a discovered device with correct MTU and discover services and setup apdu sender\", async () => {\n // given\n let scanInterval: NodeJS.Timeout | null = null;\n const bleManager = new BleManager();\n const mockDevice = {\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi.fn().mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"knownDeviceId\",\n localName: \"knownDeviceName\",\n }),\n }),\n services: vi.fn().mockResolvedValueOnce([\n {\n uuid: \"ledgerId\",\n },\n ]),\n } as unknown as Device;\n\n const startScan = vi\n .fn()\n .mockImplementation((_uuids, _options, listener) => {\n scanInterval = setInterval(() => {\n listener(null, {\n id: \"deviceId\",\n localName: \"name\",\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n });\n }, 500);\n\n listener(null, {\n id: \"43\",\n localName: \"name43\",\n serviceUUIDs: [\"notLedgerId\"],\n rssi: 43,\n });\n });\n\n const stopScan = vi.fn().mockImplementation(() => {\n if (scanInterval) {\n clearInterval(scanInterval);\n scanInterval = null;\n }\n });\n\n vi.spyOn(bleManager, \"connectedDevices\").mockImplementation(\n fakeConnectedDevices,\n );\n vi.spyOn(bleManager, \"startDeviceScan\").mockImplementation(startScan);\n vi.spyOn(bleManager, \"stopDeviceScan\").mockImplementation(stopScan);\n vi.spyOn(bleManager, \"connectToDevice\").mockResolvedValueOnce(mockDevice);\n vi.spyOn(\n bleManager,\n \"discoverAllServicesAndCharacteristicsForDevice\",\n ).mockResolvedValueOnce(mockDevice);\n vi.spyOn(bleManager, \"monitorCharacteristicForDevice\").mockImplementation(\n vi.fn(),\n );\n vi.spyOn(\n bleManager,\n \"writeCharacteristicWithoutResponseForDevice\",\n ).mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"onDeviceDisconnected\").mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"isDeviceConnected\").mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"onStateChange\").mockImplementation(\n (listener: (state: State) => void) => {\n listener(State.PoweredOn);\n return {\n remove: vi.fn(),\n };\n },\n );\n\n const fakeSetupConnection = vi.fn().mockResolvedValue(undefined);\n const deviceConnectionStateMachineFactory = vi.fn().mockReturnValue({\n sendApdu: vi.fn(),\n });\n const deviceApduSenderFactory = vi.fn().mockReturnValue({\n setupConnection: fakeSetupConnection,\n });\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n deviceConnectionStateMachineFactory,\n deviceApduSenderFactory,\n );\n\n // when\n const [device] = await lastValueFrom(\n transport.listenToAvailableDevices().pipe(take(3)),\n );\n\n const result = await transport.connect({\n deviceId: device!.id,\n onDisconnect: vi.fn(),\n });\n\n // then\n expect(result.isRight()).toBe(true);\n expect(bleManager.connectToDevice).toHaveBeenCalledWith(\"deviceId\", {\n requestMTU: 156,\n });\n expect(\n bleManager.discoverAllServicesAndCharacteristicsForDevice,\n ).toHaveBeenCalledWith(\"deviceId\");\n expect(fakeSetupConnection).toHaveBeenCalled();\n });\n\n it(\"should return a connected device which calls state machine sendApdu\", async () => {\n // given\n let scanInterval: NodeJS.Timeout | null = null;\n const bleManager = new BleManager();\n const mockDevice = {\n id: \"deviceId\",\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi.fn().mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"knownDeviceId\",\n localName: \"knownDeviceName\",\n }),\n }),\n services: vi.fn().mockResolvedValueOnce([\n {\n uuid: \"ledgerId\",\n },\n ]),\n } as unknown as Device;\n\n const startScan = vi\n .fn()\n .mockImplementation((_uuids, _options, listener) => {\n scanInterval = setInterval(() => {\n listener(null, {\n id: \"deviceId\",\n localName: \"name\",\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n });\n }, 100);\n });\n\n const stopScan = vi.fn().mockImplementation(() => {\n if (scanInterval) {\n clearInterval(scanInterval);\n scanInterval = null;\n }\n });\n\n vi.spyOn(bleManager, \"connectedDevices\").mockImplementation(\n fakeConnectedDevices,\n );\n vi.spyOn(bleManager, \"startDeviceScan\").mockImplementation(startScan);\n vi.spyOn(bleManager, \"stopDeviceScan\").mockImplementation(stopScan);\n vi.spyOn(bleManager, \"connectToDevice\").mockResolvedValueOnce(mockDevice);\n vi.spyOn(\n bleManager,\n \"discoverAllServicesAndCharacteristicsForDevice\",\n ).mockResolvedValueOnce(mockDevice);\n vi.spyOn(bleManager, \"monitorCharacteristicForDevice\").mockImplementation(\n vi.fn(),\n );\n vi.spyOn(\n bleManager,\n \"writeCharacteristicWithoutResponseForDevice\",\n ).mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"onDeviceDisconnected\").mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"isDeviceConnected\").mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"onStateChange\").mockImplementation(\n (listener: (state: State) => void) => {\n listener(State.PoweredOn);\n return {\n remove: vi.fn(),\n };\n },\n );\n\n const fakeSendApdu = vi.fn();\n const deviceConnectionStateMachineFactory = vi.fn().mockReturnValue({\n sendApdu: fakeSendApdu,\n });\n const deviceApduSenderFactory = vi.fn().mockReturnValue({\n setupConnection: vi.fn().mockResolvedValue(undefined),\n });\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n deviceConnectionStateMachineFactory,\n deviceApduSenderFactory,\n );\n\n // when\n const [device] = await lastValueFrom(\n transport.listenToAvailableDevices().pipe(take(3)),\n );\n\n const result = await transport.connect({\n deviceId: device!.id,\n onDisconnect: vi.fn(),\n });\n\n const connectedDevice = result.extract() as TransportConnectedDevice;\n connectedDevice.sendApdu(Uint8Array.from([0x43, 0x32]));\n // then\n expect(result).toEqual(\n Right(\n new TransportConnectedDevice({\n id: \"deviceId\",\n deviceModel: fakeDeviceModel,\n type: \"BLE\",\n transport: \"RN_BLE\",\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n sendApdu: expect.any(Function),\n }),\n ),\n );\n expect(fakeSendApdu).toHaveBeenCalledWith(Uint8Array.from([0x43, 0x32]));\n });\n });\n\n describe(\"disconnect\", () => {\n let fakeConnectedDevices: Mock;\n\n beforeEach(() => {\n fakeConnectedDevices = vi.fn().mockResolvedValue([\n {\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi\n .fn()\n .mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"deviceId\",\n localName: \"knownDeviceName\",\n }),\n }),\n },\n ]);\n });\n\n it(\"should disconnect gracefully\", async () => {\n let scanInterval: NodeJS.Timeout | null = null;\n const bleManager = new BleManager();\n const mockDevice = {\n id: \"deviceId\",\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi.fn().mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"knownDeviceId\",\n localName: \"knownDeviceName\",\n }),\n }),\n services: vi.fn().mockResolvedValueOnce([\n {\n uuid: \"ledgerId\",\n },\n ]),\n } as unknown as Device;\n\n const startScan = vi\n .fn()\n .mockImplementation((_uuids, _options, listener) => {\n scanInterval = setInterval(() => {\n listener(null, {\n id: \"deviceId\",\n localName: \"name\",\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n });\n }, 100);\n });\n\n const stopScan = vi.fn().mockImplementation(() => {\n if (scanInterval) {\n clearInterval(scanInterval);\n scanInterval = null;\n }\n });\n\n const onDeviceDisconnected = vi\n .fn()\n .mockImplementation((_id, callback) => {\n callback(null, {\n deviceId: \"deviceId\",\n connect: vi.fn().mockResolvedValue({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"deviceId\",\n localName: \"knownDeviceName\",\n }),\n discoverAllServicesAndCharacteristics: vi\n .fn()\n .mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"deviceId\",\n localName: \"knownDeviceName\",\n }),\n });\n return { remove: vi.fn() };\n });\n\n const fakeCloseConnection = vi.fn();\n\n vi.spyOn(bleManager, \"connectedDevices\").mockImplementation(\n fakeConnectedDevices,\n );\n vi.spyOn(bleManager, \"startDeviceScan\").mockImplementation(startScan);\n vi.spyOn(bleManager, \"stopDeviceScan\").mockImplementation(stopScan);\n vi.spyOn(bleManager, \"connectToDevice\").mockResolvedValueOnce(mockDevice);\n vi.spyOn(\n bleManager,\n \"discoverAllServicesAndCharacteristicsForDevice\",\n ).mockResolvedValueOnce(mockDevice);\n vi.spyOn(bleManager, \"monitorCharacteristicForDevice\").mockImplementation(\n vi.fn(),\n );\n vi.spyOn(\n bleManager,\n \"writeCharacteristicWithoutResponseForDevice\",\n ).mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"onDeviceDisconnected\").mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"isDeviceConnected\").mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"onStateChange\").mockImplementation(\n (listener: (state: State) => void) => {\n listener(State.PoweredOn);\n return {\n remove: vi.fn(),\n };\n },\n );\n\n vi.spyOn(bleManager, \"onDeviceDisconnected\").mockImplementation(\n onDeviceDisconnected,\n );\n vi.spyOn(bleManager, \"isDeviceConnected\").mockImplementation(vi.fn());\n\n const deviceConnectionStateMachineFactory = (\n _args: DeviceConnectionStateMachineParams<RNBleApduSenderDependencies>,\n ) => {\n return new DeviceConnectionStateMachine({\n deviceId: \"deviceId\",\n deviceApduSender: _args.deviceApduSender,\n timeoutDuration: 1000,\n onTerminated: _args.onTerminated,\n });\n };\n\n const deviceApduSenderFactory = vi.fn().mockReturnValue({\n setupConnection: vi.fn().mockResolvedValue(undefined),\n closeConnection: fakeCloseConnection,\n });\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n deviceConnectionStateMachineFactory,\n deviceApduSenderFactory,\n );\n\n const fakeOnDisconnect = vi.fn();\n\n // when\n const [device] = await lastValueFrom(\n transport.listenToAvailableDevices().pipe(take(3)),\n );\n\n const result = await transport.connect({\n deviceId: device!.id,\n onDisconnect: fakeOnDisconnect,\n });\n\n const res = await transport.disconnect({\n connectedDevice: result.extract() as TransportConnectedDevice,\n });\n\n // then\n expect(res).toEqual(Right(undefined));\n expect(fakeOnDisconnect).toHaveBeenCalled();\n expect(fakeCloseConnection).toHaveBeenCalled();\n });\n\n it(\"should handle error while disconnecting\", async () => {\n let scanInterval: NodeJS.Timeout | null = null;\n const bleManager = new BleManager();\n const mockDevice = {\n id: \"deviceId\",\n readRSSI: vi.fn().mockResolvedValueOnce({\n discoverAllServicesAndCharacteristics: vi.fn().mockResolvedValueOnce({\n services: vi.fn().mockResolvedValueOnce({}),\n serviceUUIDs: [\"ledgerId\"],\n rssi: 64,\n id: \"knownDeviceId\",\n localName: \"knownDeviceName\",\n }),\n }),\n services: vi.fn().mockResolvedValueOnce([\n {\n uuid: \"ledgerId\",\n },\n ]),\n } as unknown as Device;\n\n const startScan = vi\n .fn()\n .mockImplementation((_uuids, _options, listener) => {\n scanInterval = setInterval(() => {\n listener(null, {\n id: \"deviceId\",\n localName: \"name\",\n serviceUUIDs: [\"ledgerId\"],\n rssi: 42,\n });\n }, 100);\n });\n\n const stopScan = vi.fn().mockImplementation(() => {\n if (scanInterval) {\n clearInterval(scanInterval);\n scanInterval = null;\n }\n });\n\n const onDeviceDisconnected = vi\n .fn()\n .mockImplementation((_id, callback) => {\n callback(new Error(\"yolo\"), null);\n return { remove: vi.fn() };\n });\n\n const fakeCloseConnection = vi.fn();\n\n vi.spyOn(bleManager, \"connectedDevices\").mockImplementation(\n fakeConnectedDevices,\n );\n vi.spyOn(bleManager, \"startDeviceScan\").mockImplementation(startScan);\n vi.spyOn(bleManager, \"stopDeviceScan\").mockImplementation(stopScan);\n vi.spyOn(bleManager, \"connectToDevice\").mockResolvedValueOnce(mockDevice);\n vi.spyOn(\n bleManager,\n \"discoverAllServicesAndCharacteristicsForDevice\",\n ).mockResolvedValueOnce(mockDevice);\n vi.spyOn(bleManager, \"monitorCharacteristicForDevice\").mockImplementation(\n vi.fn(),\n );\n vi.spyOn(\n bleManager,\n \"writeCharacteristicWithoutResponseForDevice\",\n ).mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"onDeviceDisconnected\").mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"isDeviceConnected\").mockImplementation(vi.fn());\n vi.spyOn(bleManager, \"onStateChange\").mockImplementation(\n (listener: (state: State) => void) => {\n listener(State.PoweredOn);\n return {\n remove: vi.fn(),\n };\n },\n );\n\n vi.spyOn(bleManager, \"onDeviceDisconnected\").mockImplementation(\n onDeviceDisconnected,\n );\n vi.spyOn(bleManager, \"isDeviceConnected\").mockImplementation(vi.fn());\n\n const deviceConnectionStateMachineFactory = (\n _args: DeviceConnectionStateMachineParams<RNBleApduSenderDependencies>,\n ) => {\n return new DeviceConnectionStateMachine({\n deviceId: \"deviceId\",\n deviceApduSender: _args.deviceApduSender,\n timeoutDuration: 1000,\n onTerminated: _args.onTerminated,\n });\n };\n\n const deviceApduSenderFactory = vi.fn().mockReturnValue({\n setupConnection: vi.fn().mockResolvedValue(undefined),\n closeConnection: fakeCloseConnection,\n });\n\n const transport = new RNBleTransport(\n fakeDataSource as unknown as DeviceModelDataSource,\n () => fakeLogger as unknown as LoggerPublisherService,\n (() => {}) as unknown as ApduSenderServiceFactory,\n (() => {}) as unknown as ApduReceiverServiceFactory,\n bleManager,\n fakePlaftorm as Platform,\n {} as unknown as PermissionsAndroid,\n deviceConnectionStateMachineFactory,\n deviceApduSenderFactory,\n );\n\n const fakeOnDisconnect = vi.fn();\n\n // when\n const [device] = await lastValueFrom(\n transport.listenToAvailableDevices().pipe(take(3)),\n );\n const result = await transport.connect({\n deviceId: device!.id,\n onDisconnect: fakeOnDisconnect,\n });\n\n const res = await transport.disconnect({\n connectedDevice: result.extract() as TransportConnectedDevice,\n });\n\n // then\n expect(res).toEqual(Right(undefined));\n expect(fakeOnDisconnect).toHaveBeenCalled();\n });\n });\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["import_react_native_ble_plx", "import_device_management_kit", "import_purify_ts", "import_rxjs", "import_vitest", "import_Errors", "import_RNBleTransport", "fakeLogger", "expectAndroidSupportedResult", "params", "expects", "platform", "permissionsAndroid", "key", "transport", "isSupported", "fakePlaftorm", "fakeDeviceModel", "getBluetoothServicesMock", "getBluetoothServicesInfosMock", "fakeDataSource", "subscription", "bleManager", "identifier", "e", "done", "discoveredDevice", "scanInterval", "startScan", "_uuids", "_options", "listener", "stopScan", "mockDevice", "obs", "discoveredDevices", "device", "stopDeviceScan", "devices", "fakeConnectedDevices", "deviceApduSenderFactory", "result", "fakeSetupConnection", "deviceConnectionStateMachineFactory", "fakeSendApdu", "onDeviceDisconnected", "_id", "callback", "fakeCloseConnection", "_args", "fakeOnDisconnect", "res"]
|
|
7
7
|
}
|
package/lib/cjs/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ledgerhq/device-transport-kit-react-native-ble",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"private": false,
|
|
6
6
|
"exports": {
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
],
|
|
21
21
|
"scripts": {
|
|
22
22
|
"prebuild": "rimraf lib",
|
|
23
|
-
"build": "pnpm
|
|
23
|
+
"build": "pnpm ldmk-tool build --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json",
|
|
24
24
|
"dev": "concurrently \"pnpm watch:builds\" \"pnpm watch:types\"",
|
|
25
|
-
"watch:builds": "pnpm
|
|
25
|
+
"watch:builds": "pnpm ldmk-tool watch --entryPoints src/index.ts,src/**/*.ts --tsconfig tsconfig.prod.json",
|
|
26
26
|
"watch:types": "concurrently \"tsc --watch -p tsconfig.prod.json\" \"tsc-alias --watch -p tsconfig.prod.json\"",
|
|
27
27
|
"lint": "eslint",
|
|
28
28
|
"lint:fix": "pnpm lint --fix",
|
|
@@ -35,30 +35,30 @@
|
|
|
35
35
|
"test:coverage": "vitest run --coverage"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@sentry/minimal": "
|
|
39
|
-
"js-base64": "
|
|
40
|
-
"purify-ts": "
|
|
41
|
-
"uuid": "
|
|
38
|
+
"@sentry/minimal": "catalog:",
|
|
39
|
+
"js-base64": "catalog:",
|
|
40
|
+
"purify-ts": "catalog:",
|
|
41
|
+
"uuid": "catalog:"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@ledgerhq/device-management-kit": "workspace:*",
|
|
45
|
-
"@ledgerhq/esbuild-tools": "workspace:*",
|
|
46
45
|
"@ledgerhq/eslint-config-dsdk": "workspace:*",
|
|
46
|
+
"@ledgerhq/ldmk-tool": "workspace:*",
|
|
47
47
|
"@ledgerhq/prettier-config-dsdk": "workspace:*",
|
|
48
48
|
"@ledgerhq/tsconfig-dsdk": "workspace:*",
|
|
49
49
|
"@ledgerhq/vitest-config-dmk": "workspace:*",
|
|
50
|
-
"@types/uuid": "
|
|
51
|
-
"@vitejs/plugin-react": "
|
|
52
|
-
"react-native": "
|
|
53
|
-
"react-native-ble-plx": "
|
|
54
|
-
"rxjs": "
|
|
55
|
-
"ts-node": "
|
|
56
|
-
"vitest-react-native": "
|
|
50
|
+
"@types/uuid": "catalog:",
|
|
51
|
+
"@vitejs/plugin-react": "catalog:",
|
|
52
|
+
"react-native": "catalog:",
|
|
53
|
+
"react-native-ble-plx": "catalog:",
|
|
54
|
+
"rxjs": "catalog:",
|
|
55
|
+
"ts-node": "catalog:",
|
|
56
|
+
"vitest-react-native": "catalog:"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@ledgerhq/device-management-kit": "
|
|
59
|
+
"@ledgerhq/device-management-kit": "^0.7.0",
|
|
60
60
|
"react-native": ">0.74.1",
|
|
61
61
|
"react-native-ble-plx": "3.4.0",
|
|
62
|
-
"rxjs": "
|
|
62
|
+
"rxjs": "catalog:"
|
|
63
63
|
}
|
|
64
64
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const T=156,
|
|
1
|
+
const T=156,E=2e3,O=15e3,_=1e4;export{O as BLE_DISCONNECT_TIMEOUT_ANDROID,_ as BLE_DISCONNECT_TIMEOUT_IOS,E as CONNECTION_LOST_DELAY,T as DEFAULT_MTU};
|
|
2
2
|
//# sourceMappingURL=Const.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/api/model/Const.ts"],
|
|
4
|
-
"sourcesContent": ["export const DEFAULT_MTU = 156;\nexport const CONNECTION_LOST_DELAY = 2e3; // 2s;\nexport const
|
|
5
|
-
"mappings": "AAAO,MAAMA,EAAc,IACdC,EAAwB,IACxBC,
|
|
6
|
-
"names": ["DEFAULT_MTU", "CONNECTION_LOST_DELAY", "
|
|
4
|
+
"sourcesContent": ["export const DEFAULT_MTU = 156;\nexport const CONNECTION_LOST_DELAY = 2e3; // 2s;\nexport const BLE_DISCONNECT_TIMEOUT_ANDROID = 15e3; // 15s;\nexport const BLE_DISCONNECT_TIMEOUT_IOS = 10e3; // 10s;\n"],
|
|
5
|
+
"mappings": "AAAO,MAAMA,EAAc,IACdC,EAAwB,IACxBC,EAAiC,KACjCC,EAA6B",
|
|
6
|
+
"names": ["DEFAULT_MTU", "CONNECTION_LOST_DELAY", "BLE_DISCONNECT_TIMEOUT_ANDROID", "BLE_DISCONNECT_TIMEOUT_IOS"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{GeneralDmkError as
|
|
1
|
+
import{GeneralDmkError as n,OpeningConnectionError as t}from"@ledgerhq/device-management-kit";class s extends n{constructor(r){super(r);this.err=r}_tag="BleTransportNotSupportedError"}class a extends n{constructor(r){super(r);this.err=r}_tag="BleDeviceGattServerError"}class l extends n{constructor(r){super(r);this.err=r}_tag="DeviceConnectionNotFound"}class u extends n{constructor(r){super(r);this.err=r}_tag="InternalDeviceNotFound"}class c extends n{constructor(r){super(r);this.err=r}_tag="BleNotSupported"}class i extends n{constructor(r){super(r);this.err=r}_tag="NoDeviceModelFoundError"}class p extends t{constructor(r){super(r);this.err=r}_tag="PairingRefusedError"}class v extends n{constructor(r){super(r);this.err=r}_tag="UnknownBleError"}class x extends t{constructor(r){super(r);this.err=r}_tag="PeerRemovedPairingError"}export{a as BleDeviceGattServerError,c as BleNotSupported,s as BleTransportNotSupportedError,l as DeviceConnectionNotFound,u as InternalDeviceNotFound,i as NoDeviceModelFoundError,p as PairingRefusedError,x as PeerRemovedPairingError,v as UnknownBleError};
|
|
2
2
|
//# sourceMappingURL=Errors.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/api/model/Errors.ts"],
|
|
4
|
-
"sourcesContent": ["import {
|
|
5
|
-
"mappings": "AAAA,
|
|
6
|
-
"names": ["GeneralDmkError", "BleTransportNotSupportedError", "err", "BleDeviceGattServerError", "DeviceConnectionNotFound", "InternalDeviceNotFound", "BleNotSupported"]
|
|
4
|
+
"sourcesContent": ["import {\n GeneralDmkError,\n OpeningConnectionError,\n} from \"@ledgerhq/device-management-kit\";\n\nexport class BleTransportNotSupportedError extends GeneralDmkError {\n override readonly _tag = \"BleTransportNotSupportedError\";\n constructor(readonly err?: unknown) {\n super(err);\n }\n}\nexport class BleDeviceGattServerError extends GeneralDmkError {\n override readonly _tag = \"BleDeviceGattServerError\";\n constructor(readonly err?: unknown) {\n super(err);\n }\n}\nexport class DeviceConnectionNotFound extends GeneralDmkError {\n override readonly _tag = \"DeviceConnectionNotFound\";\n constructor(readonly err?: unknown) {\n super(err);\n }\n}\nexport class InternalDeviceNotFound extends GeneralDmkError {\n override readonly _tag = \"InternalDeviceNotFound\";\n constructor(readonly err?: unknown) {\n super(err);\n }\n}\n\nexport class BleNotSupported extends GeneralDmkError {\n override readonly _tag = \"BleNotSupported\";\n constructor(readonly err?: unknown) {\n super(err);\n }\n}\n\nexport class NoDeviceModelFoundError extends GeneralDmkError {\n override readonly _tag = \"NoDeviceModelFoundError\";\n constructor(readonly err?: unknown) {\n super(err);\n }\n}\n\nexport class PairingRefusedError extends OpeningConnectionError {\n override readonly _tag = \"PairingRefusedError\";\n constructor(readonly err?: unknown) {\n super(err);\n }\n}\n\nexport class UnknownBleError extends GeneralDmkError {\n override readonly _tag = \"UnknownBleError\";\n constructor(readonly err?: unknown) {\n super(err);\n }\n}\n\nexport class PeerRemovedPairingError extends OpeningConnectionError {\n override readonly _tag = \"PeerRemovedPairingError\";\n constructor(readonly err?: unknown) {\n super(err);\n }\n}\n"],
|
|
5
|
+
"mappings": "AAAA,OACE,mBAAAA,EACA,0BAAAC,MACK,kCAEA,MAAMC,UAAsCF,CAAgB,CAEjE,YAAqBG,EAAe,CAClC,MAAMA,CAAG,EADU,SAAAA,CAErB,CAHkB,KAAO,+BAI3B,CACO,MAAMC,UAAiCJ,CAAgB,CAE5D,YAAqBG,EAAe,CAClC,MAAMA,CAAG,EADU,SAAAA,CAErB,CAHkB,KAAO,0BAI3B,CACO,MAAME,UAAiCL,CAAgB,CAE5D,YAAqBG,EAAe,CAClC,MAAMA,CAAG,EADU,SAAAA,CAErB,CAHkB,KAAO,0BAI3B,CACO,MAAMG,UAA+BN,CAAgB,CAE1D,YAAqBG,EAAe,CAClC,MAAMA,CAAG,EADU,SAAAA,CAErB,CAHkB,KAAO,wBAI3B,CAEO,MAAMI,UAAwBP,CAAgB,CAEnD,YAAqBG,EAAe,CAClC,MAAMA,CAAG,EADU,SAAAA,CAErB,CAHkB,KAAO,iBAI3B,CAEO,MAAMK,UAAgCR,CAAgB,CAE3D,YAAqBG,EAAe,CAClC,MAAMA,CAAG,EADU,SAAAA,CAErB,CAHkB,KAAO,yBAI3B,CAEO,MAAMM,UAA4BR,CAAuB,CAE9D,YAAqBE,EAAe,CAClC,MAAMA,CAAG,EADU,SAAAA,CAErB,CAHkB,KAAO,qBAI3B,CAEO,MAAMO,UAAwBV,CAAgB,CAEnD,YAAqBG,EAAe,CAClC,MAAMA,CAAG,EADU,SAAAA,CAErB,CAHkB,KAAO,iBAI3B,CAEO,MAAMQ,UAAgCV,CAAuB,CAElE,YAAqBE,EAAe,CAClC,MAAMA,CAAG,EADU,SAAAA,CAErB,CAHkB,KAAO,yBAI3B",
|
|
6
|
+
"names": ["GeneralDmkError", "OpeningConnectionError", "BleTransportNotSupportedError", "err", "BleDeviceGattServerError", "DeviceConnectionNotFound", "InternalDeviceNotFound", "BleNotSupported", "NoDeviceModelFoundError", "PairingRefusedError", "UnknownBleError", "PeerRemovedPairingError"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{DeviceNotInitializedError as
|
|
1
|
+
import{DeviceNotInitializedError as l,SendApduTimeoutError as _}from"@ledgerhq/device-management-kit";import{Base64 as a}from"js-base64";import{Left as o,Maybe as p,Nothing as u,Right as f}from"purify-ts";import{BehaviorSubject as h}from"rxjs";import{PairingRefusedError as v,UnknownBleError as m}from"../model/Errors";const y=3;class w{_dependencies;_isDeviceReady;_logger;_apduSender;_apduSenderFactory;_apduReceiver;_sendApduPromiseResolver;_writeCharacteristic;_characteristicSubscription=void 0;constructor({apduSenderFactory:i,apduReceiverFactory:t,dependencies:n},r){this._dependencies=n,this._isDeviceReady=new h(!1),this._logger=r("RNBleApduSender"),this._apduSenderFactory=i,this._apduSender=u,this._apduReceiver=t(),this._sendApduPromiseResolver=u}onReceiveSetupApduResponse(i){const t=new Uint8Array(i),{device:n}=this._dependencies,[r]=t.slice(5);let e=n.mtu-y;r&&r!==e&&(e=r),this._apduSender=p.of(this._apduSenderFactory({frameSize:e})),this._isDeviceReady.next(!0)}receiveApdu(i){this._apduReceiver.handleFrame(i).map(n=>{n.map(r=>{this._logger.debug("Received APDU Response",{data:{response:r}}),this._sendApduPromiseResolver.map(e=>e(f(r)))})}).mapLeft(n=>{this._sendApduPromiseResolver.map(r=>r(o(n)))})}onMonitor(i){if(!i.value)return;const t=a.toUint8Array(i.value);this._isDeviceReady.value?this.receiveApdu(t):this.onReceiveSetupApduResponse(t)}write(i){return this._writeCharacteristic.isWritableWithoutResponse?this._writeCharacteristic.writeWithoutResponse(i):this._writeCharacteristic.writeWithResponse(i)}getDependencies(){return this._dependencies}setDependencies(i){this._dependencies=i,this._isDeviceReady=new h(!1),this._characteristicSubscription&&(this._characteristicSubscription.remove(),this._characteristicSubscription=void 0)}async setupConnection(){this._characteristicSubscription=this._dependencies.device.monitorCharacteristicForService(this._dependencies.internalDevice.bleDeviceInfos.serviceUuid,this._dependencies.internalDevice.bleDeviceInfos.notifyUuid,(e,c)=>{if(e?.message.includes("notify change failed")){this._isDeviceReady.error(new v(e)),this._logger.error("Pairing failed",{data:{error:e}});return}else e&&(this._isDeviceReady.error(new m(e)),this._logger.error("Error monitoring characteristic",{data:{error:e}}));!e&&c&&this.onMonitor(c)});const i=await this._dependencies.manager.characteristicsForDevice(this._dependencies.device.id,this._dependencies.internalDevice.bleDeviceInfos.serviceUuid);let t=i.find(e=>e.uuid===this._dependencies.internalDevice.bleDeviceInfos.writeCmdUuid);if(t)this._writeCharacteristic=t;else if(t=i.find(e=>e.uuid===this._dependencies.internalDevice.bleDeviceInfos.writeUuid),t)this._writeCharacteristic=t;else throw this._logger.error("No write characteristic found"),new Error("No write characteristic found");const n=Uint8Array.from([8,0,0,0,0]);await this.write(a.fromUint8Array(n)).catch(e=>{throw this._logger.error("Pairing failed",{data:{error:e}}),new v(e)});let r;await new Promise((e,c)=>{r&&r.unsubscribe(),r=this._isDeviceReady.subscribe({next:s=>{s&&e()},error:s=>{c(s)}})})}async sendApdu(i,t,n){if(this._logger.debug("[sendApdu]",{data:{apdu:i,abortTimeout:n}}),!this._isDeviceReady.value)return Promise.resolve(o(new l("Unknown MTU")));let r;const e=new Promise(s=>{this._sendApduPromiseResolver=p.of((...d)=>(r&&clearTimeout(r),s(...d)))}),c=this._apduSender.caseOf({Just:s=>s.getFrames(i),Nothing:()=>[]});for(const s of c)try{await this.write(a.fromUint8Array(s.getRawData()))}catch(d){this._logger.info("Error sending frame",{data:{error:d}})}return n&&(r=setTimeout(()=>{this._logger.debug("[sendApdu] Abort timeout",{data:{abortTimeout:n}}),this._sendApduPromiseResolver.map(s=>s(o(new _("Abort timeout"))))},n)),e}closeConnection(){this._dependencies.device.cancelConnection()}}export{w as RNBleApduSender};
|
|
2
2
|
//# sourceMappingURL=RNBleApduSender.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/api/transport/RNBleApduSender.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type BleManager,\n type Characteristic,\n type Device,\n type Subscription as
|
|
5
|
-
"mappings": "AAMA,OASE,6BAAAA,EAGA,wBAAAC,
|
|
6
|
-
"names": ["DeviceNotInitializedError", "SendApduTimeoutError", "Base64", "Left", "Maybe", "Nothing", "Right", "BehaviorSubject", "FRAME_HEADER_SIZE", "RNBleApduSender", "apduSenderFactory", "apduReceiverFactory", "dependencies", "loggerServiceFactory", "value", "mtuResponse", "device", "ledgerMtu", "frameSize", "apdu", "response", "apduResponse", "resolve", "error", "characteristic", "requestMtuFrame", "sub", "isReady", "_triggersDisconnection", "abortTimeout", "timeout", "resultPromise", "args", "frames", "apduSender", "frame"]
|
|
4
|
+
"sourcesContent": ["import {\n type BleManager,\n type Characteristic,\n type Device,\n type Subscription as BleCharacteristicSubscription,\n} from \"react-native-ble-plx\";\nimport {\n type ApduReceiverService,\n type ApduReceiverServiceFactory,\n type ApduResponse,\n type ApduSenderService,\n type ApduSenderServiceFactory,\n type BleDeviceInfos,\n type DeviceApduSender,\n type DeviceId,\n DeviceNotInitializedError,\n type DmkError,\n type LoggerPublisherService,\n SendApduTimeoutError,\n} from \"@ledgerhq/device-management-kit\";\nimport { Base64 } from \"js-base64\";\nimport { type Either, Left, Maybe, Nothing, Right } from \"purify-ts\";\nimport { BehaviorSubject, type Subscription } from \"rxjs\";\n\nimport { PairingRefusedError, UnknownBleError } from \"@api/model/Errors\";\n\nconst FRAME_HEADER_SIZE = 3;\n\nexport type RNBleInternalDevice = {\n id: DeviceId;\n bleDeviceInfos: BleDeviceInfos;\n};\n\nexport type RNBleApduSenderConstructorArgs = {\n dependencies: RNBleApduSenderDependencies;\n apduSenderFactory: ApduSenderServiceFactory;\n apduReceiverFactory: ApduReceiverServiceFactory;\n};\n\nexport type RNBleApduSenderDependencies = {\n device: Device;\n internalDevice: RNBleInternalDevice;\n manager: BleManager;\n};\n\nexport class RNBleApduSender\n implements DeviceApduSender<RNBleApduSenderDependencies>\n{\n private _dependencies: RNBleApduSenderDependencies;\n private _isDeviceReady: BehaviorSubject<boolean>;\n private _logger: LoggerPublisherService;\n private _apduSender: Maybe<ApduSenderService>;\n private readonly _apduSenderFactory: ApduSenderServiceFactory;\n private readonly _apduReceiver: ApduReceiverService;\n private _sendApduPromiseResolver: Maybe<\n (value: Either<DmkError, ApduResponse>) => void\n >;\n\n private _writeCharacteristic!: Characteristic;\n private _characteristicSubscription:\n | BleCharacteristicSubscription\n | undefined = undefined;\n\n constructor(\n {\n apduSenderFactory,\n apduReceiverFactory,\n dependencies,\n }: RNBleApduSenderConstructorArgs,\n loggerServiceFactory: (tag: string) => LoggerPublisherService,\n ) {\n this._dependencies = dependencies;\n this._isDeviceReady = new BehaviorSubject<boolean>(false);\n this._logger = loggerServiceFactory(\"RNBleApduSender\");\n this._apduSenderFactory = apduSenderFactory;\n this._apduSender = Nothing;\n this._apduReceiver = apduReceiverFactory();\n this._sendApduPromiseResolver = Nothing;\n }\n\n private onReceiveSetupApduResponse(value: Uint8Array) {\n const mtuResponse = new Uint8Array(value);\n const { device } = this._dependencies;\n // ledger mtu is the 5th byte of the response\n const [ledgerMtu] = mtuResponse.slice(5);\n let frameSize = device.mtu - FRAME_HEADER_SIZE;\n if (ledgerMtu && ledgerMtu !== frameSize) {\n // should never happen since ble mtu is negotiated on device connect with 156 bytes and ledger should return mtu size minus header size\n frameSize = ledgerMtu;\n }\n this._apduSender = Maybe.of(this._apduSenderFactory({ frameSize }));\n this._isDeviceReady.next(true);\n }\n\n private receiveApdu(apdu: Uint8Array) {\n const maybeApduResponse = this._apduReceiver.handleFrame(apdu);\n\n maybeApduResponse\n .map((response) => {\n response.map((apduResponse) => {\n this._logger.debug(\"Received APDU Response\", {\n data: { response: apduResponse },\n });\n this._sendApduPromiseResolver.map((resolve) =>\n resolve(Right(apduResponse)),\n );\n });\n })\n .mapLeft((error) => {\n this._sendApduPromiseResolver.map((resolve) => resolve(Left(error)));\n });\n }\n\n private onMonitor(characteristic: Characteristic) {\n if (!characteristic.value) {\n return;\n }\n\n const apdu = Base64.toUint8Array(characteristic.value);\n if (!this._isDeviceReady.value) {\n this.onReceiveSetupApduResponse(apdu);\n } else {\n this.receiveApdu(apdu);\n }\n }\n\n private write(value: string) {\n if (this._writeCharacteristic.isWritableWithoutResponse) {\n return this._writeCharacteristic.writeWithoutResponse(value);\n }\n\n return this._writeCharacteristic.writeWithResponse(value);\n }\n\n public getDependencies() {\n return this._dependencies;\n }\n\n public setDependencies(dependencies: RNBleApduSenderDependencies) {\n this._dependencies = dependencies;\n\n //Set dependencies mean we are reconnecting to a new device\n // So we need to reset the state of the sender\n this._isDeviceReady = new BehaviorSubject<boolean>(false);\n if (this._characteristicSubscription) {\n this._characteristicSubscription.remove();\n this._characteristicSubscription = undefined;\n }\n }\n\n public async setupConnection() {\n this._characteristicSubscription =\n this._dependencies.device.monitorCharacteristicForService(\n this._dependencies.internalDevice.bleDeviceInfos.serviceUuid,\n this._dependencies.internalDevice.bleDeviceInfos.notifyUuid,\n (error, characteristic) => {\n if (error?.message.includes(\"notify change failed\")) {\n // iOS pairing refused error\n this._isDeviceReady.error(new PairingRefusedError(error));\n this._logger.error(\"Pairing failed\", {\n data: { error },\n });\n return;\n } else if (error) {\n this._isDeviceReady.error(new UnknownBleError(error));\n this._logger.error(\"Error monitoring characteristic\", {\n data: { error },\n });\n }\n if (!error && characteristic) {\n this.onMonitor(characteristic);\n }\n },\n );\n\n // Setup Write characteristic\n const characteristics =\n await this._dependencies.manager.characteristicsForDevice(\n this._dependencies.device.id,\n this._dependencies.internalDevice.bleDeviceInfos.serviceUuid,\n );\n\n let tmpWriteCharacteristic = characteristics.find(\n (characteristic) =>\n characteristic.uuid ===\n this._dependencies.internalDevice.bleDeviceInfos.writeCmdUuid,\n );\n if (tmpWriteCharacteristic) {\n this._writeCharacteristic = tmpWriteCharacteristic;\n } else {\n tmpWriteCharacteristic = characteristics.find(\n (characteristic) =>\n characteristic.uuid ===\n this._dependencies.internalDevice.bleDeviceInfos.writeUuid,\n );\n\n //This should never happen\n if (tmpWriteCharacteristic) {\n this._writeCharacteristic = tmpWriteCharacteristic;\n } else {\n this._logger.error(\"No write characteristic found\");\n throw new Error(\"No write characteristic found\");\n }\n }\n\n const requestMtuFrame = Uint8Array.from([0x08, 0x00, 0x00, 0x00, 0x00]);\n await this.write(Base64.fromUint8Array(requestMtuFrame)).catch((error) => {\n // Android pairing refused error\n this._logger.error(\"Pairing failed\", {\n data: { error },\n });\n throw new PairingRefusedError(error);\n });\n let sub: Subscription | undefined;\n await new Promise<void>((resolve, reject) => {\n if (sub) {\n sub.unsubscribe();\n }\n\n sub = this._isDeviceReady.subscribe({\n next: (isReady) => {\n if (isReady) {\n resolve(); // FIXME: we should instead return a Right\n }\n },\n error: (error) => {\n reject(error); // FIXME: we should instead return a Left so it's properly typed\n },\n });\n });\n }\n\n async sendApdu(\n apdu: Uint8Array,\n _triggersDisconnection?: boolean,\n abortTimeout?: number,\n ): Promise<Either<DmkError, ApduResponse>> {\n this._logger.debug(\"[sendApdu]\", {\n data: { apdu, abortTimeout },\n });\n if (!this._isDeviceReady.value) {\n return Promise.resolve(\n Left(new DeviceNotInitializedError(\"Unknown MTU\")),\n );\n }\n\n let timeout: ReturnType<typeof setTimeout> | undefined;\n\n const resultPromise = new Promise<Either<DmkError, ApduResponse>>(\n (resolve) => {\n this._sendApduPromiseResolver = Maybe.of((...args) => {\n if (timeout) {\n clearTimeout(timeout);\n }\n return resolve(...args);\n });\n },\n );\n\n const frames = this._apduSender.caseOf({\n Just: (apduSender) => apduSender.getFrames(apdu),\n Nothing: () => [],\n });\n\n for (const frame of frames) {\n try {\n await this.write(Base64.fromUint8Array(frame.getRawData()));\n } catch (error) {\n this._logger.info(\"Error sending frame\", { data: { error } });\n }\n }\n\n if (abortTimeout) {\n timeout = setTimeout(() => {\n this._logger.debug(\"[sendApdu] Abort timeout\", {\n data: { abortTimeout },\n });\n this._sendApduPromiseResolver.map((resolve) =>\n resolve(Left(new SendApduTimeoutError(\"Abort timeout\"))),\n );\n }, abortTimeout);\n }\n\n return resultPromise;\n }\n\n public closeConnection() {\n this._dependencies.device.cancelConnection();\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["DeviceNotInitializedError", "SendApduTimeoutError", "Base64", "Left", "Maybe", "Nothing", "Right", "BehaviorSubject", "PairingRefusedError", "UnknownBleError", "FRAME_HEADER_SIZE", "RNBleApduSender", "apduSenderFactory", "apduReceiverFactory", "dependencies", "loggerServiceFactory", "value", "mtuResponse", "device", "ledgerMtu", "frameSize", "apdu", "response", "apduResponse", "resolve", "error", "characteristic", "characteristics", "tmpWriteCharacteristic", "requestMtuFrame", "sub", "reject", "isReady", "_triggersDisconnection", "abortTimeout", "timeout", "resultPromise", "args", "frames", "apduSender", "frame"]
|
|
7
7
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{defaultApduReceiverServiceStubBuilder as C,defaultApduSenderServiceStubBuilder as U,DeviceNotInitializedError as D,GeneralDmkError as A,SendApduTimeoutError as m}from"@ledgerhq/device-management-kit";import{Left as o,Maybe as w,Right as x}from"purify-ts";import{RNBleApduSender as b}from"./RNBleApduSender";vi.mock("react-native-ble-plx",()=>({BleManager:vi.fn()}));const g=3,S=156;class I{subscribers=[];tag;constructor(t,r){this.subscribers=t,this.tag=r}error=vi.fn();warn=vi.fn();info=vi.fn();debug=vi.fn()}let v,u,y,e,n;const l=vi.fn();describe("RNBleApduSender",()=>{beforeEach(()=>{v=i=>new I([],i),u=vi.fn(()=>U(void 0,v)),y=vi.fn(()=>C(void 0,v)),e=new b({dependencies:{device:{mtu:156,cancelConnection:l},internalDevice:{},manager:{}},apduReceiverFactory:y,apduSenderFactory:u},v)}),afterEach(()=>{vi.clearAllMocks()}),describe("constructor",()=>{it("should create an instance of RNBleApduSender",()=>{expect(e).toBeDefined()})}),describe("getDependencies",()=>{it("should return the dependencies",()=>{const i=e.getDependencies();expect(i).toStrictEqual({device:{mtu:156,cancelConnection:l},internalDevice:{},manager:{}})})}),describe("setDependencies",()=>{it("should set the dependencies",()=>{const i={device:{mtu:156,id:"deviceId",cancelConnection:l},internalDevice:{id:"deviceId",bleDeviceInfos:{serviceUuid:"serviceUuid",notifyUuid:"notifyUuid",writeCmdUuid:"writeCmdUuid"}},manager:{}};e.setDependencies(i);const t=e.getDependencies();expect(t).toStrictEqual(i)})}),describe("setupConnection",()=>{beforeEach(()=>{n={monitorCharacteristicForDevice:vi.fn(),writeCharacteristicWithoutResponseForDevice:vi.fn()};const i={device:{mtu:156,id:"deviceId"},internalDevice:{bleDeviceInfos:{serviceUuid:"serviceUuid",notifyUuid:"notifyUuid",writeCmdUuid:"writeCmdUuid"}},manager:n};e.setDependencies(i)}),it("should setup the connection and resolve when the device is ready",async()=>{vi.spyOn(n,"monitorCharacteristicForDevice").mockImplementation((i,t,r,c)=>(c(null,{value:"BQAAAA8BBUJPTE9TBTEuMi4ykAA="}),{remove:vi.fn()})),vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((i,t,r,c)=>(e.onMonitor({value:c}),Promise.resolve({value:c}))),await e.setupConnection(),expect(n.monitorCharacteristicForDevice).toHaveBeenCalled(),expect(n.writeCharacteristicWithoutResponseForDevice).toHaveBeenCalled()})}),describe("closeConnection",()=>{it("should close the connection",()=>{e.closeConnection(),expect(l).toHaveBeenCalled()})}),describe("sendApdu",()=>{beforeEach(async()=>{n={monitorCharacteristicForDevice:vi.fn(),writeCharacteristicWithoutResponseForDevice:vi.fn()};const i={device:{mtu:156,id:"deviceId"},internalDevice:{bleDeviceInfos:{serviceUuid:"serviceUuid",notifyUuid:"notifyUuid",writeCmdUuid:"writeCmdUuid"}},manager:n};vi.spyOn(n,"monitorCharacteristicForDevice").mockImplementationOnce((t,r,c,a)=>(a(null,{value:"BQAAAA8BBUJPTE9TBTEuMi4ykAA="}),{remove:vi.fn()})),vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((t,r,c,a)=>(e.onMonitor({value:a}),Promise.resolve({value:a}))),e.setDependencies(i),await e.setupConnection()}),describe("when the device is not ready",()=>{it("should return a DeviceNotInitializedError",async()=>{const i=new Uint8Array([8,0,0,0]);e._isDeviceReady.next(!1);const t=await e.sendApdu(i);expect(t).toStrictEqual(o(new D("Unknown MTU")))})}),describe("when the device is ready",()=>{it("should send the apdu",async()=>{const i=new Uint8Array([176,1,0,0,0]),t=new Uint8Array([5,0,0,0,15,1,5,66,79,76,79,83,5,49,46,50,46,50,144,0]),r=new Uint8Array([144,0]),c={data:t,statusCode:r};vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((d,s,f,p)=>(e.onMonitor({value:p}),Promise.resolve({value:p}))),vi.spyOn(e._apduReceiver,"handleFrame").mockImplementation(()=>x(w.of(c)));const a=await e.sendApdu(i);expect(u).toHaveBeenCalledTimes(2),expect(u).toHaveBeenNthCalledWith(1,{frameSize:1}),expect(u).toHaveBeenNthCalledWith(2,{frameSize:S-g}),expect(a).toStrictEqual(x(c))}),it("should return an error if the frame cannot be handled",async()=>{const i=new Uint8Array([176,1,0,0,0]),t=new A("could not handle frame");vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((c,a,d,s)=>(e.onMonitor({value:s}),Promise.resolve({value:s}))),vi.spyOn(e._apduReceiver,"handleFrame").mockImplementation(()=>o(t));const r=await e.sendApdu(i);expect(r).toStrictEqual(o(t))}),it("should return a SendApduTimeoutError if something takes too long",async()=>{const i=new Uint8Array([176,1,0,0,0]),t=new Uint8Array([5,0,0,0,15,1,5,66,79,76,79,83,5,49,46,50,46,50,144,0]),r=new Uint8Array([144,0]),c={data:t,statusCode:r},a=new m("Abort timeout");vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((s,f,p,h)=>(e.onMonitor({value:h}),Promise.resolve({value:h}))),vi.spyOn(e,"onMonitor").mockImplementation(()=>{setTimeout(()=>x(w.of(c)),2e3)});const d=await e.sendApdu(i,!1,100);expect(d).toStrictEqual(o(a))}),it("should and and log an error if the this.write fails",async()=>{const i=new Uint8Array([176,1,0,0,0]),t=new m("Abort timeout");vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((c,a,d,s)=>(e.onMonitor({value:s}),Promise.resolve({value:s}))),vi.spyOn(e,"write").mockImplementation(()=>Promise.reject(new Error("test")));const r=await e.sendApdu(i,!1,100);expect(r).toStrictEqual(o(t))}),it("should timeout if there are no characteristic.value",async()=>{const i=new Uint8Array([176,1,0,0,0]),t=new m("Abort timeout");vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((c,a,d,s)=>(e.onMonitor({}),Promise.resolve({}))),vi.spyOn(e,"write").mockImplementation(()=>Promise.reject(new Error("test")));const r=await e.sendApdu(i,!1,100);expect(r).toStrictEqual(o(t))})})})});
|
|
1
|
+
import{defaultApduReceiverServiceStubBuilder as C,defaultApduSenderServiceStubBuilder as U,DeviceNotInitializedError as D,GeneralDmkError as A,SendApduTimeoutError as m}from"@ledgerhq/device-management-kit";import{Left as o,Maybe as w,Right as x}from"purify-ts";import{RNBleApduSender as b}from"./RNBleApduSender";vi.mock("react-native-ble-plx",()=>({BleManager:vi.fn()}));const g=3,S=156;class I{subscribers=[];tag;constructor(t,r){this.subscribers=t,this.tag=r}error=vi.fn();warn=vi.fn();info=vi.fn();debug=vi.fn()}let v,u,y,e,n;const l=vi.fn();describe.skip("RNBleApduSender",()=>{beforeEach(()=>{v=i=>new I([],i),u=vi.fn(()=>U(void 0,v)),y=vi.fn(()=>C(void 0,v)),e=new b({dependencies:{device:{mtu:156,cancelConnection:l},internalDevice:{},manager:{}},apduReceiverFactory:y,apduSenderFactory:u},v)}),afterEach(()=>{vi.clearAllMocks()}),describe("constructor",()=>{it("should create an instance of RNBleApduSender",()=>{expect(e).toBeDefined()})}),describe("getDependencies",()=>{it("should return the dependencies",()=>{const i=e.getDependencies();expect(i).toStrictEqual({device:{mtu:156,cancelConnection:l},internalDevice:{},manager:{}})})}),describe("setDependencies",()=>{it("should set the dependencies",()=>{const i={device:{mtu:156,id:"deviceId",cancelConnection:l},internalDevice:{id:"deviceId",bleDeviceInfos:{serviceUuid:"serviceUuid",notifyUuid:"notifyUuid",writeCmdUuid:"writeCmdUuid"}},manager:{}};e.setDependencies(i);const t=e.getDependencies();expect(t).toStrictEqual(i)})}),describe("setupConnection",()=>{beforeEach(()=>{n={monitorCharacteristicForDevice:vi.fn(),writeCharacteristicWithoutResponseForDevice:vi.fn()};const i={device:{mtu:156,id:"deviceId"},internalDevice:{bleDeviceInfos:{serviceUuid:"serviceUuid",notifyUuid:"notifyUuid",writeCmdUuid:"writeCmdUuid"}},manager:n};e.setDependencies(i)}),it("should setup the connection and resolve when the device is ready",async()=>{vi.spyOn(n,"monitorCharacteristicForDevice").mockImplementation((i,t,r,c)=>(c(null,{value:"BQAAAA8BBUJPTE9TBTEuMi4ykAA="}),{remove:vi.fn()})),vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((i,t,r,c)=>(e.onMonitor({value:c}),Promise.resolve({value:c}))),await e.setupConnection(),expect(n.monitorCharacteristicForDevice).toHaveBeenCalled(),expect(n.writeCharacteristicWithoutResponseForDevice).toHaveBeenCalled()})}),describe("closeConnection",()=>{it("should close the connection",()=>{e.closeConnection(),expect(l).toHaveBeenCalled()})}),describe("sendApdu",()=>{beforeEach(async()=>{n={monitorCharacteristicForDevice:vi.fn(),writeCharacteristicWithoutResponseForDevice:vi.fn()};const i={device:{mtu:156,id:"deviceId"},internalDevice:{bleDeviceInfos:{serviceUuid:"serviceUuid",notifyUuid:"notifyUuid",writeCmdUuid:"writeCmdUuid"}},manager:n};vi.spyOn(n,"monitorCharacteristicForDevice").mockImplementationOnce((t,r,c,a)=>(a(null,{value:"BQAAAA8BBUJPTE9TBTEuMi4ykAA="}),{remove:vi.fn()})),vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((t,r,c,a)=>(e.onMonitor({value:a}),Promise.resolve({value:a}))),e.setDependencies(i),await e.setupConnection()}),describe("when the device is not ready",()=>{it("should return a DeviceNotInitializedError",async()=>{const i=new Uint8Array([8,0,0,0]);e._isDeviceReady.next(!1);const t=await e.sendApdu(i);expect(t).toStrictEqual(o(new D("Unknown MTU")))})}),describe("when the device is ready",()=>{it("should send the apdu",async()=>{const i=new Uint8Array([176,1,0,0,0]),t=new Uint8Array([5,0,0,0,15,1,5,66,79,76,79,83,5,49,46,50,46,50,144,0]),r=new Uint8Array([144,0]),c={data:t,statusCode:r};vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((d,s,f,p)=>(e.onMonitor({value:p}),Promise.resolve({value:p}))),vi.spyOn(e._apduReceiver,"handleFrame").mockImplementation(()=>x(w.of(c)));const a=await e.sendApdu(i);expect(u).toHaveBeenCalledTimes(2),expect(u).toHaveBeenNthCalledWith(1,{frameSize:1}),expect(u).toHaveBeenNthCalledWith(2,{frameSize:S-g}),expect(a).toStrictEqual(x(c))}),it("should return an error if the frame cannot be handled",async()=>{const i=new Uint8Array([176,1,0,0,0]),t=new A("could not handle frame");vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((c,a,d,s)=>(e.onMonitor({value:s}),Promise.resolve({value:s}))),vi.spyOn(e._apduReceiver,"handleFrame").mockImplementation(()=>o(t));const r=await e.sendApdu(i);expect(r).toStrictEqual(o(t))}),it("should return a SendApduTimeoutError if something takes too long",async()=>{const i=new Uint8Array([176,1,0,0,0]),t=new Uint8Array([5,0,0,0,15,1,5,66,79,76,79,83,5,49,46,50,46,50,144,0]),r=new Uint8Array([144,0]),c={data:t,statusCode:r},a=new m("Abort timeout");vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((s,f,p,h)=>(e.onMonitor({value:h}),Promise.resolve({value:h}))),vi.spyOn(e,"onMonitor").mockImplementation(()=>{setTimeout(()=>x(w.of(c)),2e3)});const d=await e.sendApdu(i,!1,100);expect(d).toStrictEqual(o(a))}),it("should and and log an error if the this.write fails",async()=>{const i=new Uint8Array([176,1,0,0,0]),t=new m("Abort timeout");vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((c,a,d,s)=>(e.onMonitor({value:s}),Promise.resolve({value:s}))),vi.spyOn(e,"write").mockImplementation(()=>Promise.reject(new Error("test")));const r=await e.sendApdu(i,!1,100);expect(r).toStrictEqual(o(t))}),it("should timeout if there are no characteristic.value",async()=>{const i=new Uint8Array([176,1,0,0,0]),t=new m("Abort timeout");vi.spyOn(n,"writeCharacteristicWithoutResponseForDevice").mockImplementation((c,a,d,s)=>(e.onMonitor({}),Promise.resolve({}))),vi.spyOn(e,"write").mockImplementation(()=>Promise.reject(new Error("test")));const r=await e.sendApdu(i,!1,100);expect(r).toStrictEqual(o(t))})})})});
|
|
2
2
|
//# sourceMappingURL=RNBleApduSender.test.js.map
|