@onekeyfe/hd-transport-react-native 1.2.0-alpha.18 → 1.2.0-alpha.180

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.
@@ -1,13 +1,2 @@
1
- import type { ProtocolType } from '@onekeyfe/hd-transport';
2
- export declare function createTransportCallLog(name: string, protocol: ProtocolType, data: Record<string, unknown>): {
3
- name: string;
4
- protocol: ProtocolType;
5
- file_name: unknown;
6
- hash: unknown;
7
- } | {
8
- name: string;
9
- protocol: ProtocolType;
10
- file_name?: undefined;
11
- hash?: undefined;
12
- };
1
+ export { createTransportCallLog } from '@onekeyfe/hd-transport';
13
2
  //# sourceMappingURL=transportLog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transportLog.d.ts","sourceRoot":"","sources":["../src/transportLog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;;;;;;;;;EAY9B"}
1
+ {"version":3,"file":"transportLog.d.ts","sourceRoot":"","sources":["../src/transportLog.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/types.d.ts CHANGED
@@ -7,5 +7,6 @@ export type BleAcquireInput = {
7
7
  uuid: string;
8
8
  forceCleanRunPromise?: boolean;
9
9
  expectedProtocol?: ProtocolType;
10
+ protocolHint?: ProtocolType;
10
11
  };
11
12
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,YAAY,EAAE,UAAU,IAAI,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAExE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,gBAAgB,CAAC,EAAE,YAAY,CAAC;CACjC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAE3D,YAAY,EAAE,UAAU,IAAI,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAExE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,gBAAgB,CAAC,EAAE,YAAY,CAAC;IAChC,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC"}
package/jest.config.js ADDED
@@ -0,0 +1,10 @@
1
+ module.exports = {
2
+ preset: '../../jest.config.js',
3
+ testEnvironment: 'node',
4
+ modulePathIgnorePatterns: ['node_modules', '<rootDir>/dist'],
5
+ moduleNameMapper: {
6
+ // The workspace symlinks resolve to prebuilt dist outputs that can lag behind src.
7
+ '^@onekeyfe/hd-transport$': '<rootDir>/../hd-transport/src/index.ts',
8
+ '^@onekeyfe/hd-shared$': '<rootDir>/../shared/src/index.ts',
9
+ },
10
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-transport-react-native",
3
- "version": "1.2.0-alpha.18",
3
+ "version": "1.2.0-alpha.180",
4
4
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -15,15 +15,16 @@
15
15
  "scripts": {
16
16
  "dev": "rimraf dist && rollup -c ../../build/rollup.config.js -w",
17
17
  "build": "rimraf dist && rollup -c ../../build/rollup.config.js",
18
+ "test": "jest",
18
19
  "lint": "eslint .",
19
20
  "lint:fix": "eslint . --fix"
20
21
  },
21
22
  "dependencies": {
22
- "@onekeyfe/hd-core": "1.2.0-alpha.18",
23
- "@onekeyfe/hd-shared": "1.2.0-alpha.18",
24
- "@onekeyfe/hd-transport": "1.2.0-alpha.18",
23
+ "@onekeyfe/hd-core": "1.2.0-alpha.180",
24
+ "@onekeyfe/hd-shared": "1.2.0-alpha.180",
25
+ "@onekeyfe/hd-transport": "1.2.0-alpha.180",
25
26
  "@onekeyfe/react-native-ble-utils": "^0.1.6",
26
27
  "react-native-ble-plx": "3.5.1"
27
28
  },
28
- "gitHead": "bdbc5bf74e48ca90f5c56f3079b2b974e61f7aa4"
29
+ "gitHead": "37976e13bb904ec6167ccba67a7b497e5a3744a2"
29
30
  }
@@ -1,12 +1,5 @@
1
- import { BleErrorCode } from 'react-native-ble-plx';
2
- import { wait } from '@onekeyfe/hd-shared';
3
-
4
- import { bleLogger } from './logger';
5
-
6
1
  import type { Characteristic, Device, Subscription } from 'react-native-ble-plx';
7
2
 
8
- const Log = bleLogger;
9
-
10
3
  export default class BleTransport {
11
4
  id: string;
12
5
 
@@ -14,7 +7,7 @@ export default class BleTransport {
14
7
 
15
8
  device: Device;
16
9
 
17
- mtuSize = 23;
10
+ mtuSize: number | undefined;
18
11
 
19
12
  writeCharacteristic: Characteristic;
20
13
 
@@ -28,10 +21,6 @@ export default class BleTransport {
28
21
 
29
22
  monitorToken?: number;
30
23
 
31
- static MAX_RETRIES = 5;
32
-
33
- static RETRY_DELAY = 2000;
34
-
35
24
  constructor(
36
25
  device: Device,
37
26
  writeCharacteristic: Characteristic,
@@ -44,36 +33,15 @@ export default class BleTransport {
44
33
  }
45
34
 
46
35
  /**
47
- * @description only for pro / touch , while upgrade firmware
48
- * @param data
49
- * @param retryCount
50
- * @returns
36
+ * Bulk-transfer write (Protocol V1 FirmwareUpload / EmmcFileWrite only).
37
+ *
38
+ * Must stay writeWithoutResponse on every platform. writeWithResponse serialises
39
+ * each packet into its own connection-interval round trip, which on iOS turned a
40
+ * 1.7MB firmware upload (~13.5k packets) into a >10 minute transfer that never
41
+ * finished before the app-level timeout. Protocol V2 and ordinary V1 control
42
+ * messages pick their write type separately and are unaffected by this method.
51
43
  */
52
- async writeWithRetry(data: string, retryCount = BleTransport.MAX_RETRIES): Promise<void> {
53
- try {
54
- await this.writeCharacteristic.writeWithoutResponse(data);
55
- } catch (error) {
56
- Log?.debug(
57
- `Write retry attempt ${BleTransport.MAX_RETRIES - retryCount + 1}, error: ${error}`
58
- );
59
- if (retryCount > 0) {
60
- await wait(BleTransport.RETRY_DELAY);
61
- if (
62
- error.errorCode === BleErrorCode.DeviceDisconnected ||
63
- error.errorCode === BleErrorCode.CharacteristicNotFound
64
- ) {
65
- try {
66
- await this.device.connect();
67
- await this.device.discoverAllServicesAndCharacteristics();
68
- } catch (e) {
69
- Log?.debug(`Connect or discoverAllServicesAndCharacteristics error: ${e}`);
70
- }
71
- } else {
72
- Log?.debug(`writeCharacteristic error: ${error}`);
73
- }
74
- return this.writeWithRetry(data, retryCount - 1);
75
- }
76
- throw error;
77
- }
44
+ async writeWithRetry(data: string): Promise<void> {
45
+ await this.writeCharacteristic.writeWithoutResponse(data);
78
46
  }
79
47
  }
@@ -0,0 +1,114 @@
1
+ import { BleErrorCode } from 'react-native-ble-plx';
2
+ import { Platform } from 'react-native';
3
+
4
+ import BleTransport from '../BleTransport';
5
+
6
+ jest.mock(
7
+ 'react-native',
8
+ () => ({
9
+ Platform: { OS: 'ios' },
10
+ }),
11
+ { virtual: true }
12
+ );
13
+
14
+ jest.mock(
15
+ 'react-native-ble-plx',
16
+ () => ({
17
+ BleErrorCode: {
18
+ DeviceDisconnected: 205,
19
+ CharacteristicNotFound: 404,
20
+ },
21
+ }),
22
+ { virtual: true }
23
+ );
24
+
25
+ jest.mock('@onekeyfe/hd-shared', () => ({
26
+ ...jest.requireActual('@onekeyfe/hd-shared'),
27
+ wait: jest.fn(() => Promise.resolve()),
28
+ }));
29
+
30
+ describe('BleTransport side-effecting writes', () => {
31
+ beforeEach(() => {
32
+ Platform.OS = 'ios';
33
+ });
34
+
35
+ test('does not reconnect or replay after the device disconnects', async () => {
36
+ const error = Object.assign(new Error('device disconnected'), {
37
+ errorCode: BleErrorCode.DeviceDisconnected,
38
+ });
39
+ const writeCharacteristic = {
40
+ isWritableWithResponse: true,
41
+ writeWithResponse: jest.fn(() => Promise.resolve()),
42
+ writeWithoutResponse: jest.fn(() => Promise.reject(error)),
43
+ };
44
+ const device = {
45
+ id: 'classic-id',
46
+ connect: jest.fn(() => Promise.resolve()),
47
+ discoverAllServicesAndCharacteristics: jest.fn(() => Promise.resolve()),
48
+ };
49
+ const transport = new BleTransport(device as any, writeCharacteristic as any, {} as any);
50
+
51
+ await expect(transport.writeWithRetry('payload')).rejects.toBe(error);
52
+
53
+ expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledTimes(1);
54
+ expect(device.connect).not.toHaveBeenCalled();
55
+ });
56
+
57
+ test('keeps iOS bulk transfer on writeWithoutResponse even when the characteristic supports responses', async () => {
58
+ // writeWithResponse serialises every packet into its own connection-interval
59
+ // round trip. On a ~1.7MB firmware (~13.5k packets) that stalled the upload past
60
+ // the 600s app-level timeout, so bulk transfer must never opt into it.
61
+ const writeCharacteristic = {
62
+ isWritableWithResponse: true,
63
+ writeWithResponse: jest.fn(() => Promise.resolve()),
64
+ writeWithoutResponse: jest.fn(() => Promise.resolve()),
65
+ };
66
+ const transport = new BleTransport(
67
+ { id: 'classic-id' } as any,
68
+ writeCharacteristic as any,
69
+ {} as any
70
+ );
71
+
72
+ await transport.writeWithRetry('payload');
73
+
74
+ expect(writeCharacteristic.writeWithResponse).not.toHaveBeenCalled();
75
+ expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledWith('payload');
76
+ });
77
+
78
+ test('keeps Android Protocol V1 writes on writeWithoutResponse', async () => {
79
+ Platform.OS = 'android';
80
+ const writeCharacteristic = {
81
+ isWritableWithResponse: true,
82
+ writeWithResponse: jest.fn(() => Promise.resolve()),
83
+ writeWithoutResponse: jest.fn(() => Promise.resolve()),
84
+ };
85
+ const transport = new BleTransport(
86
+ { id: 'classic-id' } as any,
87
+ writeCharacteristic as any,
88
+ {} as any
89
+ );
90
+
91
+ await transport.writeWithRetry('payload');
92
+
93
+ expect(writeCharacteristic.writeWithResponse).not.toHaveBeenCalled();
94
+ expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledWith('payload');
95
+ });
96
+
97
+ test('uses writeWithoutResponse on iOS when the characteristic lacks response support', async () => {
98
+ const writeCharacteristic = {
99
+ isWritableWithResponse: false,
100
+ writeWithResponse: jest.fn(() => Promise.resolve()),
101
+ writeWithoutResponse: jest.fn(() => Promise.resolve()),
102
+ };
103
+ const transport = new BleTransport(
104
+ { id: 'classic-id' } as any,
105
+ writeCharacteristic as any,
106
+ {} as any
107
+ );
108
+
109
+ await transport.writeWithRetry('payload');
110
+
111
+ expect(writeCharacteristic.writeWithResponse).not.toHaveBeenCalled();
112
+ expect(writeCharacteristic.writeWithoutResponse).toHaveBeenCalledWith('payload');
113
+ });
114
+ });
@@ -1,4 +1,9 @@
1
- import { hasWritableCapability, resolveProtocolV2PacketCapacity } from '../bleStrategy';
1
+ import {
2
+ hasWritableCapability,
3
+ resolveProtocolV2PacketCapacity,
4
+ shouldRefreshNegotiatedMtu,
5
+ shouldWriteProtocolV2WithResponse,
6
+ } from '../bleStrategy';
2
7
 
3
8
  describe('React Native BLE strategy', () => {
4
9
  test('accepts writeWithoutResponse-only characteristics', () => {
@@ -10,27 +15,52 @@ describe('React Native BLE strategy', () => {
10
15
  expect(hasWritableCapability(characteristic)).toBe(true);
11
16
  });
12
17
 
13
- test('falls back to Android default ATT payload when MTU is unavailable', () => {
18
+ test('uses the conservative ATT payload when MTU is unavailable', () => {
14
19
  expect(
15
20
  resolveProtocolV2PacketCapacity({
16
21
  platform: 'android',
17
- androidPacketLength: 192,
18
22
  mtu: null,
19
23
  })
20
24
  ).toBe(20);
21
25
  });
22
26
 
27
+ test('only refreshes an unavailable or default MTU snapshot', () => {
28
+ expect(shouldRefreshNegotiatedMtu(undefined)).toBe(true);
29
+ expect(shouldRefreshNegotiatedMtu(23)).toBe(true);
30
+ expect(shouldRefreshNegotiatedMtu(185)).toBe(false);
31
+ expect(shouldRefreshNegotiatedMtu(247)).toBe(false);
32
+ });
33
+
23
34
  test('caps Android packet length by negotiated MTU payload', () => {
24
35
  expect(
25
36
  resolveProtocolV2PacketCapacity({
26
37
  platform: 'android',
27
- androidPacketLength: 192,
38
+ androidPacketLength: 244,
28
39
  mtu: 100,
29
40
  })
30
41
  ).toBe(97);
31
42
  });
32
43
 
33
- test('keeps iOS packet length controlled by tuning profile', () => {
44
+ test('keeps the default Android packet length within the validated ceiling', () => {
45
+ expect(
46
+ resolveProtocolV2PacketCapacity({
47
+ platform: 'android',
48
+ mtu: 517,
49
+ })
50
+ ).toBe(244);
51
+ });
52
+
53
+ test('allows an explicit Android packet length override for validated experiments', () => {
54
+ expect(
55
+ resolveProtocolV2PacketCapacity({
56
+ platform: 'android',
57
+ androidPacketLength: 514,
58
+ mtu: 517,
59
+ })
60
+ ).toBe(514);
61
+ });
62
+
63
+ test('caps iOS packet length by the system-negotiated write payload', () => {
34
64
  expect(
35
65
  resolveProtocolV2PacketCapacity({
36
66
  platform: 'ios',
@@ -39,4 +69,62 @@ describe('React Native BLE strategy', () => {
39
69
  })
40
70
  ).toBe(244);
41
71
  });
72
+
73
+ test('uses the reported iOS MTU without a compatibility fallback', () => {
74
+ expect(
75
+ resolveProtocolV2PacketCapacity({
76
+ platform: 'ios',
77
+ iosPacketLength: 128,
78
+ mtu: 23,
79
+ })
80
+ ).toBe(20);
81
+ });
82
+
83
+ test('uses a smaller system-negotiated iOS write payload', () => {
84
+ expect(
85
+ resolveProtocolV2PacketCapacity({
86
+ platform: 'ios',
87
+ iosPacketLength: 244,
88
+ mtu: 185,
89
+ })
90
+ ).toBe(182);
91
+ });
92
+
93
+ test('uses withoutResponse for a high-volume write unless explicitly overridden', () => {
94
+ const characteristic = {
95
+ isWritableWithResponse: true,
96
+ isWritableWithoutResponse: true,
97
+ };
98
+
99
+ expect(
100
+ shouldWriteProtocolV2WithResponse({
101
+ platform: 'ios',
102
+ highThroughput: true,
103
+ requestedWithResponse: false,
104
+ characteristic,
105
+ })
106
+ ).toBe(false);
107
+ expect(
108
+ shouldWriteProtocolV2WithResponse({
109
+ platform: 'ios',
110
+ highThroughput: true,
111
+ requestedWithResponse: true,
112
+ characteristic,
113
+ })
114
+ ).toBe(true);
115
+ });
116
+
117
+ test('falls back to withResponse when withoutResponse is unavailable', () => {
118
+ expect(
119
+ shouldWriteProtocolV2WithResponse({
120
+ platform: 'ios',
121
+ highThroughput: true,
122
+ requestedWithResponse: false,
123
+ characteristic: {
124
+ isWritableWithResponse: true,
125
+ isWritableWithoutResponse: false,
126
+ },
127
+ })
128
+ ).toBe(true);
129
+ });
42
130
  });