@onekeyfe/hd-core 1.2.0-alpha.133 → 1.2.0-alpha.134

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.
@@ -800,13 +800,7 @@ describe('DeviceCommands cancellation', () => {
800
800
  try {
801
801
  const commands = createCommands();
802
802
  commands.disposed = false;
803
- commands.mainId = 'main-id';
804
803
  commands.callPromise = new Promise(() => {});
805
- const disconnect = jest.fn().mockResolvedValue(undefined);
806
- commands.transport = {
807
- name: 'ReactNativeBleTransport',
808
- disconnect,
809
- } as any;
810
804
  const dispose = jest.fn().mockResolvedValue(undefined);
811
805
  commands.dispose = dispose;
812
806
 
@@ -816,7 +810,6 @@ describe('DeviceCommands cancellation', () => {
816
810
 
817
811
  await expect(cancellation).resolves.toBeUndefined();
818
812
  expect(dispose).toHaveBeenCalledWith(true);
819
- expect(disconnect).toHaveBeenCalledWith('main-id');
820
813
  expect(commands.callPromise).toBeUndefined();
821
814
  } finally {
822
815
  jest.useRealTimers();
@@ -1,7 +1,7 @@
1
- import { EDeviceType, ERRORS, HardwareErrorCode, createDeferred } from '@onekeyfe/hd-shared';
1
+ import { EDeviceType, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
2
  import { DeviceType, TRANSPORT_EVENT } from '@onekeyfe/hd-transport';
3
3
 
4
- import { initConnector, initCore, isMissingDetectedProtocolV2Error } from '../src/core';
4
+ import { initConnector, initCore } from '../src/core';
5
5
  import { DataManager } from '../src/data-manager';
6
6
  import TransportManager from '../src/data-manager/TransportManager';
7
7
  import { Device } from '../src/device/Device';
@@ -82,23 +82,6 @@ describe('public device lifecycle events', () => {
82
82
  expect(DevicePool.emitter.listenerCount(DEVICE.DISCONNECT)).toBe(1);
83
83
  });
84
84
 
85
- test('isolates pending cancellation cleanup by connect id', () => {
86
- core = initCore();
87
- const context = (core as any).getCoreContext();
88
- const firstCleanup = createDeferred<void>();
89
- const replacementCleanup = createDeferred<void>();
90
-
91
- context.setPrePendingCallPromise('device-a', firstCleanup.promise);
92
-
93
- expect(context.getPrePendingCallPromise('device-a')).toBe(firstCleanup.promise);
94
- expect(context.getPrePendingCallPromise('device-b')).toBeUndefined();
95
-
96
- context.setPrePendingCallPromise('device-a', replacementCleanup.promise);
97
- context.removePrePendingCallPromise('device-a', firstCleanup.promise);
98
-
99
- expect(context.getPrePendingCallPromise('device-a')).toBe(replacementCleanup.promise);
100
- });
101
-
102
85
  test('keeps shared device lifecycle listeners across a device cache reset', () => {
103
86
  jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
104
87
  core = initCore();
@@ -251,22 +234,6 @@ describe('public device lifecycle events', () => {
251
234
  expect(device.getProtocol()).toBe('V2');
252
235
  });
253
236
 
254
- test.each([
255
- ['V2', true],
256
- ['V1', false],
257
- ] as const)(
258
- 'retries a missing detected protocol only for an explicit Protocol %s connection',
259
- (connectProtocol, expected) => {
260
- const method = { payload: { connectProtocol } } as never;
261
- const error = {
262
- errorCode: HardwareErrorCode.RuntimeError,
263
- message: 'Device protocol has not been detected for ble-id',
264
- };
265
-
266
- expect(isMissingDetectedProtocolV2Error(method, error)).toBe(expected);
267
- }
268
- );
269
-
270
237
  test('converts an internal transport disconnect into a public KnownDevice snapshot', () => {
271
238
  jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
272
239
  core = initCore();
@@ -343,62 +310,6 @@ describe('public device lifecycle events', () => {
343
310
  }
344
311
  );
345
312
 
346
- test('sends a fallback Cancel for an acquired Protocol V2 BLE call without a prompt callback', async () => {
347
- jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
348
- const device = createInitializedDevice('V2');
349
- const post = jest.fn().mockResolvedValue(undefined);
350
- const cancelDevice = jest.fn(() => cancelDeviceInPrompt(device, false));
351
- const cancel = jest.fn().mockResolvedValue(undefined);
352
- (device as unknown as { deviceAcquired: boolean }).deviceAcquired = true;
353
- device.commands = {
354
- transport: { post },
355
- cancelDevice,
356
- cancel,
357
- } as never;
358
-
359
- await device.interruptionFromUser();
360
-
361
- expect(cancelDevice).toHaveBeenCalledTimes(1);
362
- expect(post).toHaveBeenCalledWith(device.mainId, 'Cancel', {});
363
- expect(cancel).toHaveBeenCalledTimes(1);
364
- });
365
-
366
- test('waits for the canceled run to finish releasing before cancellation completes', async () => {
367
- jest.spyOn(DataManager, 'getSettings').mockReturnValue('react-native' as never);
368
- const device = createInitializedDevice('V2');
369
- const operation = createDeferred<void>();
370
- const releaseGate = createDeferred<void>();
371
- const cancelError = ERRORS.TypedError(HardwareErrorCode.DeviceInterruptedFromUser);
372
- const release = jest.spyOn(device, 'release').mockImplementation(() => releaseGate.promise);
373
- device.commands = {
374
- disposed: false,
375
- cancel: jest.fn(() => {
376
- operation.reject(cancelError);
377
- return Promise.resolve();
378
- }),
379
- } as never;
380
- (device as unknown as { deviceAcquired: boolean }).deviceAcquired = true;
381
-
382
- const runResult = device.run(() => operation.promise).catch(error => error);
383
- const cancellation = device.interruptionFromUser();
384
- let cancellationCompleted = false;
385
- cancellation.then(() => {
386
- cancellationCompleted = true;
387
- });
388
-
389
- await new Promise(resolve => {
390
- setImmediate(resolve);
391
- });
392
- expect(release).toHaveBeenCalledTimes(1);
393
- expect(cancellationCompleted).toBe(false);
394
-
395
- releaseGate.resolve();
396
- await cancellation;
397
- await expect(runResult).resolves.toMatchObject({
398
- errorCode: HardwareErrorCode.DeviceInterruptedFromUser,
399
- });
400
- });
401
-
402
313
  test.each([
403
314
  [EDeviceType.Pro2, 'webusb', false, DeviceType.PRO2],
404
315
  [EDeviceType.Neo, 'webusb', false, DeviceType.NEO],
@@ -2,9 +2,6 @@ import { EDeviceType, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
2
  import { DeviceSettingsPage } from '@onekeyfe/hd-transport';
3
3
 
4
4
  import DeviceSettings from '../src/api/device/DeviceSettings';
5
- import { Device } from '../src/device/Device';
6
- import { DEVICE } from '../src/events';
7
- import { PROTOCOL_V2_DEVICE_STATUS_GET_MESSAGE_TYPE } from '../src/protocols/protocol-v2';
8
5
  import { DEVICE_SETTINGS_NEVER_TIMEOUT_MS } from '../src/utils/deviceSettings';
9
6
 
10
7
  import type { Features } from '../src/types';
@@ -24,9 +21,6 @@ function createDevice({ protocol }: { protocol: 'V1' | 'V2' }) {
24
21
  const typedCall = jest.fn().mockResolvedValue({ message: { message: 'Success' } });
25
22
  const updateState = jest.fn();
26
23
  const getDeviceState = jest.fn();
27
- const refreshProtocolV2SettingsAfterMutation = jest.fn(() =>
28
- getDeviceState({ refreshSections: ['status', 'settings'] })
29
- );
30
24
  return {
31
25
  device: {
32
26
  features,
@@ -35,7 +29,6 @@ function createDevice({ protocol }: { protocol: 'V1' | 'V2' }) {
35
29
  commands: { typedCall },
36
30
  updateState,
37
31
  getDeviceState,
38
- refreshProtocolV2SettingsAfterMutation,
39
32
  },
40
33
  typedCall,
41
34
  updateState,
@@ -188,98 +181,7 @@ describe('DeviceSettings protocol routing', () => {
188
181
  expect(updateState).not.toHaveBeenCalled();
189
182
  });
190
183
 
191
- it('reconciles stale passphrase and label after an unrelated Protocol V2 setting change', async () => {
192
- const typedCall = jest.fn().mockImplementation((requestType: string) => {
193
- if (requestType === 'DeviceSettingsSet') {
194
- return { message: { message: 'Success' } };
195
- }
196
- if (requestType === 'DeviceStatusGet') {
197
- return {
198
- message: {
199
- init_states: true,
200
- unlocked: false,
201
- passphrase_enabled: false,
202
- },
203
- };
204
- }
205
- if (requestType === 'DeviceSettingsGet') {
206
- return {
207
- message: {
208
- label: 'Current Label',
209
- brightness: 80,
210
- passphrase_enable: false,
211
- },
212
- };
213
- }
214
- throw new Error(`Unexpected request: ${requestType}`);
215
- });
216
- const device = Device.fromDescriptor({
217
- id: 'pro2',
218
- path: 'pro2',
219
- protocolType: 'V2',
220
- } as never);
221
- (device as any).commands = { typedCall };
222
- device.updateState(
223
- {
224
- protocol: 'V2',
225
- identity: {
226
- deviceType: EDeviceType.Pro2,
227
- label: 'Stale Label',
228
- },
229
- status: {
230
- mode: 'normal',
231
- unlocked: false,
232
- passphraseProtection: true,
233
- },
234
- settings: { brightness: 20 },
235
- raw: {
236
- protocolV2ProtocolInfo: {
237
- version: 1,
238
- build_fingerprint: 'application__5.0.0__abcdef0__PROD__RELEASE',
239
- supported_messages: [PROTOCOL_V2_DEVICE_STATUS_GET_MESSAGE_TYPE],
240
- },
241
- },
242
- },
243
- 'initialize'
244
- );
245
- const onState = jest.fn();
246
- device.on(DEVICE.STATE, onState);
247
- const method = new DeviceSettings({
248
- id: 3,
249
- payload: {
250
- method: 'deviceSettings',
251
- brightness: 80,
252
- },
253
- });
254
- method.init();
255
- (method as any).device = device;
256
-
257
- await expect(method.run()).resolves.toEqual({ message: 'Success' });
258
-
259
- expect(typedCall.mock.calls.map(call => call[0])).toEqual([
260
- 'DeviceSettingsSet',
261
- 'DeviceStatusGet',
262
- 'DeviceSettingsGet',
263
- ]);
264
- expect(device.state).toMatchObject({
265
- identity: { label: 'Current Label' },
266
- status: { passphraseProtection: false },
267
- settings: { brightness: 80 },
268
- });
269
- expect(onState).toHaveBeenLastCalledWith(
270
- device,
271
- expect.objectContaining({
272
- source: 'settings-read',
273
- state: expect.objectContaining({
274
- identity: expect.objectContaining({ label: 'Current Label' }),
275
- status: expect.objectContaining({ passphraseProtection: false }),
276
- settings: expect.objectContaining({ brightness: 80 }),
277
- }),
278
- })
279
- );
280
- });
281
-
282
- it('uses the Pro2 passphrase page and refreshes device state after the toggle', async () => {
184
+ it('uses the Pro2 passphrase page as a device-side toggle and verifies the target state', async () => {
283
185
  const { device, typedCall, getDeviceState } = createDevice({ protocol: 'V2' });
284
186
  getDeviceState
285
187
  .mockResolvedValueOnce({
@@ -361,8 +263,8 @@ describe('DeviceSettings protocol routing', () => {
361
263
  expect(getDeviceState).toHaveBeenCalledWith({ refreshSections: ['settings'] });
362
264
  });
363
265
 
364
- it('does not overwrite Pro2 passphrase state when refreshed state does not match', async () => {
365
- const { device, getDeviceState, updateState } = createDevice({ protocol: 'V2' });
266
+ it('rejects a successful Pro2 page response when the hardware did not reach the target', async () => {
267
+ const { device, getDeviceState } = createDevice({ protocol: 'V2' });
366
268
  getDeviceState.mockResolvedValue({
367
269
  status: { passphraseProtection: false },
368
270
  });
@@ -376,12 +278,14 @@ describe('DeviceSettings protocol routing', () => {
376
278
  method.init();
377
279
  (method as any).device = device;
378
280
 
379
- await expect(method.run()).resolves.toEqual({ message: 'Success' });
380
- expect(updateState).not.toHaveBeenCalled();
281
+ await expect(method.run()).rejects.toMatchObject({
282
+ errorCode: HardwareErrorCode.RuntimeError,
283
+ message: 'Protocol V2 passphrase setting did not reach the requested value.',
284
+ });
381
285
  });
382
286
 
383
- it('keeps the previous Pro2 passphrase state when refreshed state is unavailable after locking', async () => {
384
- const { device, getDeviceState, updateState } = createDevice({ protocol: 'V2' });
287
+ it('accepts a locked Pro2 as confirmation after disabling passphrase', async () => {
288
+ const { device, getDeviceState } = createDevice({ protocol: 'V2' });
385
289
  getDeviceState
386
290
  .mockResolvedValueOnce({
387
291
  status: { unlocked: true, passphraseProtection: true },
@@ -400,68 +304,6 @@ describe('DeviceSettings protocol routing', () => {
400
304
  (method as any).device = device;
401
305
 
402
306
  await expect(method.run()).resolves.toEqual({ message: 'Success' });
403
- expect(updateState).not.toHaveBeenCalled();
404
- });
405
-
406
- it('preserves confirmed Pro2 passphrase state when the post-toggle status is locked', async () => {
407
- let statusReadCount = 0;
408
- const typedCall = jest.fn().mockImplementation((requestType: string) => {
409
- if (requestType === 'DeviceStatusGet') {
410
- statusReadCount += 1;
411
- return {
412
- message:
413
- statusReadCount === 1
414
- ? { init_states: true, unlocked: true, passphrase_enabled: true }
415
- : { init_states: true, unlocked: false, passphrase_enabled: false },
416
- };
417
- }
418
- if (requestType === 'DeviceSettingsPageShow') {
419
- return { message: { message: 'Success' } };
420
- }
421
- if (requestType === 'DeviceSettingsGet') {
422
- return { message: { label: 'Pro 2' } };
423
- }
424
- throw new Error(`Unexpected request: ${requestType}`);
425
- });
426
- const device = Device.fromDescriptor({
427
- id: 'pro2-passphrase',
428
- path: 'pro2-passphrase',
429
- protocolType: 'V2',
430
- } as never);
431
- (device as any).commands = { typedCall };
432
- device.updateState(
433
- {
434
- protocol: 'V2',
435
- identity: { deviceType: EDeviceType.Pro2 },
436
- status: {
437
- mode: 'normal',
438
- unlocked: true,
439
- passphraseProtection: true,
440
- },
441
- raw: {
442
- protocolV2ProtocolInfo: {
443
- version: 1,
444
- supported_messages: [PROTOCOL_V2_DEVICE_STATUS_GET_MESSAGE_TYPE],
445
- },
446
- },
447
- },
448
- 'initialize'
449
- );
450
- const method = new DeviceSettings({
451
- id: 6,
452
- payload: {
453
- method: 'deviceSettings',
454
- usePassphrase: false,
455
- },
456
- });
457
- method.init();
458
- (method as any).device = device;
459
-
460
- await expect(method.run()).resolves.toEqual({ message: 'Success' });
461
- expect(device.state?.status).toMatchObject({
462
- unlocked: false,
463
- passphraseProtection: true,
464
- });
465
307
  });
466
308
 
467
309
  it('keeps Protocol V1 passphrase settings on ApplySettings', async () => {
@@ -352,7 +352,7 @@ describe('Protocol V1 wallet identity initialization', () => {
352
352
  jest.restoreAllMocks();
353
353
  });
354
354
 
355
- test('verifies the live device id without resetting the cached wallet session', async () => {
355
+ test('purges cached sessions and rejects when the live device identity changes', async () => {
356
356
  const device = Device.fromDescriptor({ id: 'connect-b', path: 'connect-b' } as never);
357
357
  device.features = {
358
358
  protocol: 'V1',
@@ -363,7 +363,7 @@ describe('Protocol V1 wallet identity initialization', () => {
363
363
  deviceWalletSessionStore.set('cached-device-a', 'hidden-a', 'session-a');
364
364
  const typedCall = jest.fn().mockResolvedValue({
365
365
  type: 'Features',
366
- message: { device_id: 'live-device-b' },
366
+ message: { device_id: 'live-device-b', session_id: 'wrong-device-session' },
367
367
  });
368
368
  device.commands = { typedCall } as never;
369
369
  jest.spyOn(TransportManager, 'reconfigure').mockResolvedValue(undefined);
@@ -371,11 +371,76 @@ describe('Protocol V1 wallet identity initialization', () => {
371
371
  await expect(
372
372
  device.initialize({ deviceId: 'cached-device-a', passphraseState: 'hidden-a' })
373
373
  ).rejects.toMatchObject({ errorCode: HardwareErrorCode.DeviceCheckDeviceIdError });
374
+ // Identity is validated from the single Initialize round trip; no separate
375
+ // GetFeatures preflight.
374
376
  expect(typedCall).toHaveBeenCalledTimes(1);
375
- expect(typedCall).toHaveBeenCalledWith('GetFeatures', 'Features', {});
377
+ expect(typedCall).toHaveBeenCalledWith(
378
+ 'Initialize',
379
+ 'Features',
380
+ expect.objectContaining({ passphrase_state: 'hidden-a' }),
381
+ expect.any(Object)
382
+ );
383
+ // Identity change purges the previous device's cached sessions (pre-existing
384
+ // reconcileDeviceIdentity behavior — never carry sessions across devices)…
385
+ expect(deviceWalletSessionStore.get('cached-device-a', 'hidden-a')).toBeUndefined();
386
+ // …and the session the mismatched Initialize cached under the wrong
387
+ // device's identity is dropped as well.
388
+ expect(deviceWalletSessionStore.get('live-device-b', 'hidden-a')).toBeUndefined();
376
389
  });
377
390
 
378
- test('resumes a cached V1 wallet after a non-destructive live identity read', async () => {
391
+ test('drops the wrong-device session even when reconfigure fails after Initialize', async () => {
392
+ const device = Device.fromDescriptor({ id: 'connect-b', path: 'connect-b' } as never);
393
+ device.features = {
394
+ protocol: 'V1',
395
+ deviceId: 'cached-device-a',
396
+ unlocked: true,
397
+ passphraseProtection: true,
398
+ } as never;
399
+ deviceWalletSessionStore.set('cached-device-a', 'hidden-a', 'session-a');
400
+ const typedCall = jest.fn().mockResolvedValue({
401
+ type: 'Features',
402
+ message: { device_id: 'live-device-b', session_id: 'wrong-device-session' },
403
+ });
404
+ device.commands = { typedCall } as never;
405
+ // Pre-encode resync succeeds; the post-response reconfigure inside
406
+ // callInitialize rejects — the session write has already happened by then.
407
+ jest
408
+ .spyOn(TransportManager, 'reconfigure')
409
+ .mockResolvedValueOnce(undefined)
410
+ .mockRejectedValueOnce(new Error('configure failed'));
411
+
412
+ await expect(
413
+ device.initialize({ deviceId: 'cached-device-a', passphraseState: 'hidden-a' })
414
+ ).rejects.toMatchObject({ errorCode: HardwareErrorCode.DeviceCheckDeviceIdError });
415
+ // The wrong-device session must not survive the error path either.
416
+ expect(deviceWalletSessionStore.get('live-device-b', 'hidden-a')).toBeUndefined();
417
+ });
418
+
419
+ test('re-syncs the V1 message schema for this device before encoding Initialize', async () => {
420
+ const device = Device.fromDescriptor({ id: 'connect-a', path: 'connect-a' } as never);
421
+ device.features = {
422
+ protocol: 'V1',
423
+ deviceId: 'device-a',
424
+ unlocked: true,
425
+ passphraseProtection: true,
426
+ } as never;
427
+ const typedCall = jest.fn().mockResolvedValue({
428
+ type: 'Features',
429
+ message: { device_id: 'device-a' },
430
+ });
431
+ device.commands = { typedCall } as never;
432
+ const reconfigure = jest.spyOn(TransportManager, 'reconfigure').mockResolvedValue(undefined);
433
+
434
+ await device.initialize({ deviceId: 'device-a', passphraseState: 'hidden-a' });
435
+
436
+ // A stale process-global schema (from another device) would silently strip
437
+ // passphrase_state from the wire message, so the resync must come first.
438
+ expect(reconfigure.mock.invocationCallOrder[0]).toBeLessThan(
439
+ typedCall.mock.invocationCallOrder[0]
440
+ );
441
+ });
442
+
443
+ test('resumes a cached V1 wallet with a single identity-validated Initialize', async () => {
379
444
  const device = Device.fromDescriptor({ id: 'connect-a', path: 'connect-a' } as never);
380
445
  device.features = {
381
446
  protocol: 'V1',
@@ -384,22 +449,17 @@ describe('Protocol V1 wallet identity initialization', () => {
384
449
  passphraseProtection: true,
385
450
  } as never;
386
451
  deviceWalletSessionStore.set('device-a', 'hidden-a', 'session-a');
387
- const typedCall = jest
388
- .fn()
389
- .mockResolvedValueOnce({ type: 'Features', message: { device_id: 'device-a' } })
390
- .mockResolvedValueOnce({
391
- type: 'Features',
392
- message: { device_id: 'device-a', session_id: 'session-a' },
393
- });
452
+ const typedCall = jest.fn().mockResolvedValueOnce({
453
+ type: 'Features',
454
+ message: { device_id: 'device-a', session_id: 'session-a' },
455
+ });
394
456
  device.commands = { typedCall } as never;
395
457
  jest.spyOn(TransportManager, 'reconfigure').mockResolvedValue(undefined);
396
458
 
397
459
  await device.initialize({ deviceId: 'device-a', passphraseState: 'hidden-a' });
398
460
 
399
- expect(typedCall).toHaveBeenCalledTimes(2);
400
- expect(typedCall).toHaveBeenNthCalledWith(1, 'GetFeatures', 'Features', {});
401
- expect(typedCall).toHaveBeenNthCalledWith(
402
- 2,
461
+ expect(typedCall).toHaveBeenCalledTimes(1);
462
+ expect(typedCall).toHaveBeenCalledWith(
403
463
  'Initialize',
404
464
  'Features',
405
465
  expect.objectContaining({
@@ -408,9 +468,10 @@ describe('Protocol V1 wallet identity initialization', () => {
408
468
  }),
409
469
  expect.any(Object)
410
470
  );
471
+ expect(deviceWalletSessionStore.get('device-a', 'hidden-a')).toBe('session-a');
411
472
  });
412
473
 
413
- test('selects the standard V1 wallet after a non-destructive live identity read', async () => {
474
+ test('selects the standard V1 wallet with a single identity-validated Initialize', async () => {
414
475
  const device = Device.fromDescriptor({ id: 'connect-a', path: 'connect-a' } as never);
415
476
  device.features = {
416
477
  protocol: 'V1',
@@ -420,17 +481,14 @@ describe('Protocol V1 wallet identity initialization', () => {
420
481
  } as never;
421
482
  const typedCall = jest
422
483
  .fn()
423
- .mockResolvedValueOnce({ type: 'Features', message: { device_id: 'device-a' } })
424
484
  .mockResolvedValueOnce({ type: 'Features', message: { device_id: 'device-a' } });
425
485
  device.commands = { typedCall } as never;
426
486
  jest.spyOn(TransportManager, 'reconfigure').mockResolvedValue(undefined);
427
487
 
428
488
  await device.initialize({ deviceId: 'device-a' });
429
489
 
430
- expect(typedCall).toHaveBeenCalledTimes(2);
431
- expect(typedCall).toHaveBeenNthCalledWith(1, 'GetFeatures', 'Features', {});
432
- expect(typedCall).toHaveBeenNthCalledWith(
433
- 2,
490
+ expect(typedCall).toHaveBeenCalledTimes(1);
491
+ expect(typedCall).toHaveBeenCalledWith(
434
492
  'Initialize',
435
493
  'Features',
436
494
  {
@@ -183,7 +183,6 @@ describe('DeviceUploadWallpaper', () => {
183
183
  stubDevice({
184
184
  ...device,
185
185
  ensureProtocolV2RuntimeContext: jest.fn().mockResolvedValue(wallpaperProtocolInfo),
186
- refreshProtocolV2SettingsAfterMutation: jest.fn().mockResolvedValue({}),
187
186
  });
188
187
 
189
188
  test('encodes, uploads and applies a Pro2 wallpaper', async () => {
@@ -205,8 +204,7 @@ describe('DeviceUploadWallpaper', () => {
205
204
  jpegBase64: createJpegBase64(604, 1024),
206
205
  },
207
206
  });
208
- const device = stubWallpaperDevice({ commands: { typedCall } });
209
- (method as any).device = device;
207
+ (method as any).device = stubWallpaperDevice({ commands: { typedCall } });
210
208
  method.postMessage = jest.fn();
211
209
 
212
210
  method.init();
@@ -226,7 +224,6 @@ describe('DeviceUploadWallpaper', () => {
226
224
  expect(typedCall).toHaveBeenLastCalledWith('DeviceSettingsSet', 'Success', {
227
225
  settings: { wallpaper_path: result.path },
228
226
  });
229
- expect(device.refreshProtocolV2SettingsAfterMutation).toHaveBeenCalledTimes(1);
230
227
  expect(typedCall.mock.calls.some(call => call[0] === 'SetWallpaper')).toBe(false);
231
228
  expect(result).toMatchObject({ colorFormat: 'RGB565', message: 'wallpaper applied' });
232
229
  const fileWriteCallCount = typedCall.mock.calls.filter(
@@ -265,36 +262,6 @@ describe('DeviceUploadWallpaper', () => {
265
262
  expect(typedCall.mock.calls.some(call => call[0] === 'DeviceSettingsSet')).toBe(false);
266
263
  });
267
264
 
268
- test('returns success when wallpaper read-back fails after apply', async () => {
269
- const typedCall = jest.fn().mockImplementation((request, _response, params) => {
270
- if (request === 'FilesystemDirMake') return { message: {} };
271
- if (request === 'FilesystemFileWrite') {
272
- const file = params.file as { data: Uint8Array; offset: number };
273
- return { message: { processed_byte: file.offset + file.data.byteLength } };
274
- }
275
- if (request === 'DeviceSettingsSet') {
276
- return { message: { message: 'wallpaper applied' } };
277
- }
278
- throw new Error(`Unexpected request: ${request}`);
279
- });
280
- const method = new DeviceUploadWallpaper({
281
- id: 1,
282
- payload: {
283
- method: 'deviceUploadWallpaper',
284
- jpegBase64: createJpegBase64(604, 1024),
285
- },
286
- });
287
- const device = stubWallpaperDevice({ commands: { typedCall } });
288
- device.refreshProtocolV2SettingsAfterMutation.mockRejectedValueOnce(
289
- new Error('settings read-back failed')
290
- );
291
- (method as any).device = device;
292
- method.init();
293
-
294
- await expect(method.run()).resolves.toMatchObject({ message: 'wallpaper applied' });
295
- expect(device.refreshProtocolV2SettingsAfterMutation).toHaveBeenCalledTimes(1);
296
- });
297
-
298
265
  test('rejects unsafe filenames before device communication', () => {
299
266
  const method = new DeviceUploadWallpaper({
300
267
  id: 1,
@@ -1 +1 @@
1
- {"version":3,"file":"DeviceSettings.d.ts","sourceRoot":"","sources":["../../../src/api/device/DeviceSettings.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAgB3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AA0D5D,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,UAAU,CAAC,aAAa,CAAC;IACnE,qBAAqB;IAIrB,IAAI;IA0EJ,eAAe;;;;;;;IAWT,GAAG;CA2HV"}
1
+ {"version":3,"file":"DeviceSettings.d.ts","sourceRoot":"","sources":["../../../src/api/device/DeviceSettings.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAgB3C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AA0D5D,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,UAAU,CAAC,aAAa,CAAC;IACnE,qBAAqB;IAIrB,IAAI;IA0EJ,eAAe;;;;;;;IAWT,GAAG;CAyIV"}
@@ -1 +1 @@
1
- {"version":3,"file":"DeviceUploadWallpaper.d.ts","sourceRoot":"","sources":["../../../src/api/protocol-v2/DeviceUploadWallpaper.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAO3C,OAAO,EAGL,KAAK,wBAAwB,EAE9B,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,2BAA2B,GAAG;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,wBAAwB,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAmBF,MAAM,CAAC,OAAO,OAAO,qBAAsB,SAAQ,UAAU,CAAC,2BAA2B,CAAC;IACxF,qBAAqB;IAIrB,OAAO,CAAC,OAAO,CAAC,CAA8D;IAE9E,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,QAAQ,CAAS;IAEzB,OAAO,CAAC,IAAI,CAAM;IAElB,IAAI;YAwBU,kBAAkB;YAgBlB,eAAe;YAaf,MAAM;IAwBd,GAAG,IAAI,OAAO,CAAC,6BAA6B,CAAC;CAyBpD"}
1
+ {"version":3,"file":"DeviceUploadWallpaper.d.ts","sourceRoot":"","sources":["../../../src/api/protocol-v2/DeviceUploadWallpaper.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAM3C,OAAO,EAGL,KAAK,wBAAwB,EAE9B,MAAM,2BAA2B,CAAC;AAEnC,MAAM,MAAM,2BAA2B,GAAG;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,6BAA6B,GAAG;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,wBAAwB,CAAC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAkBF,MAAM,CAAC,OAAO,OAAO,qBAAsB,SAAQ,UAAU,CAAC,2BAA2B,CAAC;IACxF,qBAAqB;IAIrB,OAAO,CAAC,OAAO,CAAC,CAA8D;IAE9E,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,QAAQ,CAAS;IAEzB,OAAO,CAAC,IAAI,CAAM;IAElB,IAAI;YAwBU,kBAAkB;YAgBlB,eAAe;YAaf,MAAM;IAwBd,GAAG,IAAI,OAAO,CAAC,6BAA6B,CAAC;CAgBpD"}
@@ -5,10 +5,8 @@ import DeviceConnector from '../device/DeviceConnector';
5
5
  import type { ConnectSettings } from '../types';
6
6
  import type { CoreMessage } from '../events';
7
7
  import type { LowlevelTransportSharedPlugin } from '@onekeyfe/hd-transport';
8
- import type { BaseMethod } from '../api/BaseMethod';
9
8
  export type CoreContext = ReturnType<Core['getCoreContext']>;
10
9
  export declare const callAPI: (context: CoreContext, message: CoreMessage) => Promise<any>;
11
- export declare function isMissingDetectedProtocolV2Error(method: BaseMethod, error: unknown): boolean;
12
10
  export declare const cancel: (context: CoreContext, connectId?: string) => void;
13
11
  export declare const onDeviceButtonHandler: (__0_0: Device, __0_1: import("../events").DeviceButtonRequestPayload) => void;
14
12
  export default class Core extends EventEmitter {
@@ -16,7 +14,7 @@ export default class Core extends EventEmitter {
16
14
  readonly sdkInstanceId: string;
17
15
  private requestQueue;
18
16
  private disposePromise?;
19
- private prePendingCallPromises;
17
+ private prePendingCallPromise;
20
18
  private methodSynchronize;
21
19
  constructor();
22
20
  private getCoreContext;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAoClC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAsB1C,OAAO,eAAe,MAAM,2BAA2B,CAAC;AAYxD,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,UAAU,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAmD,MAAM,WAAW,CAAC;AAI9F,OAAO,KAAK,EACV,6BAA6B,EAG9B,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAWpD,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAmE7D,eAAO,MAAM,OAAO,YAAmB,WAAW,WAAW,WAAW,iBAoFvE,CAAC;AA2qBF,wBAAgB,gCAAgC,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,WAQlF;AAsPD,eAAO,MAAM,MAAM,YAAa,WAAW,cAAc,MAAM,SAqF9D,CAAC;AAmGF,eAAO,MAAM,qBAAqB,gFAejC,CAAC;AAiLF,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,YAAY;IAC5C,OAAO,CAAC,cAAc,CAAoB;IAE1C,SAAgB,aAAa,EAAE,MAAM,CAAC;IAEtC,OAAO,CAAC,YAAY,CAAsB;IAE1C,OAAO,CAAC,cAAc,CAAC,CAAgB;IAGvC,OAAO,CAAC,sBAAsB,CAAoC;IAElE,OAAO,CAAC,iBAAiB,CAAoB;;IAS7C,OAAO,CAAC,cAAc;IA6BhB,aAAa,CAAC,OAAO,EAAE,WAAW;IAuExC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAOV,gBAAgB;CAiC/B;AAED,eAAO,MAAM,QAAQ,YAIpB,CAAC;AAEF,eAAO,MAAM,aAAa,uBAYzB,CAAC;AAMF,eAAO,MAAM,IAAI,aACL,eAAe,aACd,GAAG,WACL,6BAA6B,8BAiBvC,CAAC;AAEF,eAAO,MAAM,eAAe;SAKrB,eAAe,CAAC,KAAK,CAAC;eAChB,GAAG;;UASf,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AAoClC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAsB1C,OAAO,eAAe,MAAM,2BAA2B,CAAC;AAYxD,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,UAAU,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAmD,MAAM,WAAW,CAAC;AAI9F,OAAO,KAAK,EACV,6BAA6B,EAG9B,MAAM,wBAAwB,CAAC;AAWhC,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AAmE7D,eAAO,MAAM,OAAO,YAAmB,WAAW,WAAW,WAAW,iBAoFvE,CAAC;AA44BF,eAAO,MAAM,MAAM,YAAa,WAAW,cAAc,MAAM,SAkF9D,CAAC;AAmGF,eAAO,MAAM,qBAAqB,gFAejC,CAAC;AAiLF,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,YAAY;IAC5C,OAAO,CAAC,cAAc,CAAoB;IAE1C,SAAgB,aAAa,EAAE,MAAM,CAAC;IAEtC,OAAO,CAAC,YAAY,CAAsB;IAE1C,OAAO,CAAC,cAAc,CAAC,CAAgB;IAGvC,OAAO,CAAC,qBAAqB,CAA4B;IAEzD,OAAO,CAAC,iBAAiB,CAAoB;;IAS7C,OAAO,CAAC,cAAc;IAoBhB,aAAa,CAAC,OAAO,EAAE,WAAW;IAuExC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAOV,gBAAgB;CAiC/B;AAED,eAAO,MAAM,QAAQ,YAIpB,CAAC;AAEF,eAAO,MAAM,aAAa,uBAYzB,CAAC;AAMF,eAAO,MAAM,IAAI,aACL,eAAe,aACd,GAAG,WACL,6BAA6B,8BAiBvC,CAAC;AAEF,eAAO,MAAM,eAAe;SAKrB,eAAe,CAAC,KAAK,CAAC;eAChB,GAAG;;UASf,CAAC"}
@@ -80,7 +80,6 @@ export declare class Device extends EventEmitter {
80
80
  get features(): Features | undefined;
81
81
  set features(features: Features | undefined);
82
82
  runPromise?: Deferred<void> | null;
83
- private runCleanupPromise?;
84
83
  externalState: string[];
85
84
  unavailableCapabilities: UnavailableCapabilities;
86
85
  instance: number;
@@ -149,7 +148,6 @@ export declare class Device extends EventEmitter {
149
148
  private _initializeProtocolV2;
150
149
  getFeatures(): Promise<Features | undefined>;
151
150
  getDeviceState(params?: DeviceStateReadOptions): Promise<import("../types").DeviceState>;
152
- refreshProtocolV2SettingsAfterMutation(): Promise<import("../types").DeviceState>;
153
151
  _updateFeatures(protoFeatures: PROTO.Features | Features, initSession?: boolean): void;
154
152
  updateState(patch: DeviceStatePatch, source: DeviceStateUpdateSource): import("../types").DeviceState & {
155
153
  raw?: import("../types").DeviceFeaturesRaw | undefined;