@onekeyfe/hd-core 1.2.0-alpha.68 → 1.2.0-alpha.69

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.
Files changed (121) hide show
  1. package/__tests__/check-all-firmware-release-protocol-v2.test.ts +28 -0
  2. package/__tests__/connectSettings.test.ts +5 -47
  3. package/__tests__/firmware-update/firmware-update-v2-download-before-boot.test.ts +31 -59
  4. package/__tests__/protocol-v2-firmware-targets.test.ts +33 -1
  5. package/__tests__/protocol-v2-resources.test.ts +9 -6
  6. package/__tests__/protocol-v2.test.ts +174 -383
  7. package/__tests__/protocolV2FileWrite.test.ts +48 -7
  8. package/dist/api/CheckAllFirmwareRelease.d.ts +2 -1
  9. package/dist/api/CheckAllFirmwareRelease.d.ts.map +1 -1
  10. package/dist/api/FirmwareUpdate.d.ts.map +1 -1
  11. package/dist/api/FirmwareUpdateV2.d.ts +0 -10
  12. package/dist/api/FirmwareUpdateV2.d.ts.map +1 -1
  13. package/dist/api/FirmwareUpdateV3.d.ts +3 -7
  14. package/dist/api/FirmwareUpdateV3.d.ts.map +1 -1
  15. package/dist/api/FirmwareUpdateV4.d.ts +6 -25
  16. package/dist/api/FirmwareUpdateV4.d.ts.map +1 -1
  17. package/dist/api/device/DeviceUpdateBootloader.d.ts +1 -5
  18. package/dist/api/device/DeviceUpdateBootloader.d.ts.map +1 -1
  19. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts +0 -8
  20. package/dist/api/firmware/FirmwareUpdateBaseMethod.d.ts.map +1 -1
  21. package/dist/api/firmware/getBinary.d.ts +0 -7
  22. package/dist/api/firmware/getBinary.d.ts.map +1 -1
  23. package/dist/api/firmware/updateBootloader.d.ts +0 -2
  24. package/dist/api/firmware/updateBootloader.d.ts.map +1 -1
  25. package/dist/api/firmware/uploadFirmware.d.ts +1 -9
  26. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -1
  27. package/dist/api/helpers/protocolV2FileWrite.d.ts.map +1 -1
  28. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  29. package/dist/data-manager/DataManager.d.ts +0 -1
  30. package/dist/data-manager/DataManager.d.ts.map +1 -1
  31. package/dist/data-manager/connectSettings.d.ts.map +1 -1
  32. package/dist/device/Device.d.ts +0 -1
  33. package/dist/device/Device.d.ts.map +1 -1
  34. package/dist/index.d.ts +2 -180
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +1041 -3037
  37. package/dist/inject.d.ts.map +1 -1
  38. package/dist/lowLevelInject.d.ts.map +1 -1
  39. package/dist/protocols/protocol-v2/resources.d.ts +1 -1
  40. package/dist/protocols/protocol-v2/resources.d.ts.map +1 -1
  41. package/dist/topLevelInject.d.ts.map +1 -1
  42. package/dist/types/api/checkAllFirmwareRelease.d.ts +0 -4
  43. package/dist/types/api/checkAllFirmwareRelease.d.ts.map +1 -1
  44. package/dist/types/api/deviceUpdateBootloader.d.ts +0 -6
  45. package/dist/types/api/deviceUpdateBootloader.d.ts.map +1 -1
  46. package/dist/types/api/export.d.ts +1 -4
  47. package/dist/types/api/export.d.ts.map +1 -1
  48. package/dist/types/api/firmwareUpdate.d.ts +0 -68
  49. package/dist/types/api/firmwareUpdate.d.ts.map +1 -1
  50. package/dist/types/api/index.d.ts +1 -9
  51. package/dist/types/api/index.d.ts.map +1 -1
  52. package/dist/types/settings.d.ts +1 -14
  53. package/dist/types/settings.d.ts.map +1 -1
  54. package/dist/utils/deviceFeaturesCompat.d.ts +0 -1
  55. package/dist/utils/deviceFeaturesCompat.d.ts.map +1 -1
  56. package/package.json +4 -4
  57. package/src/api/CheckAllFirmwareRelease.ts +25 -61
  58. package/src/api/FirmwareUpdate.ts +1 -13
  59. package/src/api/FirmwareUpdateV2.ts +121 -296
  60. package/src/api/FirmwareUpdateV3.ts +57 -263
  61. package/src/api/FirmwareUpdateV4.ts +287 -865
  62. package/src/api/device/DeviceUpdateBootloader.ts +6 -125
  63. package/src/api/firmware/FirmwareUpdateBaseMethod.ts +1 -72
  64. package/src/api/firmware/updateBootloader.ts +4 -19
  65. package/src/api/firmware/uploadFirmware.ts +22 -140
  66. package/src/api/helpers/protocolV2FileWrite.ts +54 -4
  67. package/src/data-manager/DataManager.ts +54 -59
  68. package/src/data-manager/connectSettings.ts +0 -11
  69. package/src/device/Device.ts +1 -6
  70. package/src/index.ts +0 -5
  71. package/src/inject.ts +2 -22
  72. package/src/lowLevelInject.ts +1 -5
  73. package/src/protocols/protocol-v2/resources.ts +5 -1
  74. package/src/topLevelInject.ts +1 -5
  75. package/src/types/api/checkAllFirmwareRelease.ts +0 -4
  76. package/src/types/api/deviceUpdateBootloader.ts +0 -6
  77. package/src/types/api/export.ts +0 -18
  78. package/src/types/api/firmwareUpdate.ts +0 -75
  79. package/src/types/api/index.ts +0 -14
  80. package/src/types/settings.ts +2 -14
  81. package/src/utils/deviceFeaturesCompat.ts +0 -6
  82. package/__tests__/device-initialize-timeout.test.ts +0 -56
  83. package/__tests__/firmware-update/check-all-firmware-release.test.ts +0 -175
  84. package/__tests__/firmware-update/device-update-bootloader.test.ts +0 -87
  85. package/__tests__/firmware-update/firmware-artifact-source.test.ts +0 -119
  86. package/__tests__/firmware-update/firmware-host-binding.test.ts +0 -70
  87. package/__tests__/firmware-update/firmware-preparation-error.test.ts +0 -27
  88. package/__tests__/firmware-update/firmware-update-bootloader-poll.test.ts +0 -200
  89. package/__tests__/firmware-update/firmware-update-capabilities.test.ts +0 -13
  90. package/__tests__/firmware-update/firmware-update-plan-bootloader-identity.test.ts +0 -394
  91. package/__tests__/firmware-update/firmware-update-plan.test.ts +0 -593
  92. package/__tests__/firmware-update/firmware-update-prepared-plan.test.ts +0 -231
  93. package/__tests__/firmware-update/firmware-update-v3-reconnect.test.ts +0 -63
  94. package/__tests__/firmware-update/firmware-upload-source.test.ts +0 -70
  95. package/dist/api/firmware/FirmwareArtifactSource.d.ts +0 -25
  96. package/dist/api/firmware/FirmwareArtifactSource.d.ts.map +0 -1
  97. package/dist/api/firmware/FirmwareHostBinding.d.ts +0 -6
  98. package/dist/api/firmware/FirmwareHostBinding.d.ts.map +0 -1
  99. package/dist/api/firmware/FirmwarePreparationError.d.ts +0 -3
  100. package/dist/api/firmware/FirmwarePreparationError.d.ts.map +0 -1
  101. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts +0 -3
  102. package/dist/api/firmware/FirmwareUpdateCapabilities.d.ts.map +0 -1
  103. package/dist/api/firmware/FirmwareUpdatePlan.d.ts +0 -25
  104. package/dist/api/firmware/FirmwareUpdatePlan.d.ts.map +0 -1
  105. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts +0 -32
  106. package/dist/api/firmware/FirmwareUpdatePreparedPlan.d.ts.map +0 -1
  107. package/dist/types/api/firmwareUpdateCapabilities.d.ts +0 -9
  108. package/dist/types/api/firmwareUpdateCapabilities.d.ts.map +0 -1
  109. package/dist/types/api/firmwareUpdatePlan.d.ts +0 -28
  110. package/dist/types/api/firmwareUpdatePlan.d.ts.map +0 -1
  111. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts +0 -42
  112. package/dist/types/api/firmwareUpdatePreparedPlan.d.ts.map +0 -1
  113. package/src/api/firmware/FirmwareArtifactSource.ts +0 -278
  114. package/src/api/firmware/FirmwareHostBinding.ts +0 -100
  115. package/src/api/firmware/FirmwarePreparationError.ts +0 -12
  116. package/src/api/firmware/FirmwareUpdateCapabilities.ts +0 -9
  117. package/src/api/firmware/FirmwareUpdatePlan.ts +0 -772
  118. package/src/api/firmware/FirmwareUpdatePreparedPlan.ts +0 -449
  119. package/src/types/api/firmwareUpdateCapabilities.ts +0 -9
  120. package/src/types/api/firmwareUpdatePlan.ts +0 -38
  121. package/src/types/api/firmwareUpdatePreparedPlan.ts +0 -53
@@ -163,6 +163,34 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
163
163
  });
164
164
  });
165
165
 
166
+ test('marks SE03 and SE04 as unsupported in a Neo firmware plan', () => {
167
+ const neoRelease: IFirmwareReleaseInfo = {
168
+ ...release,
169
+ installOrder: ['se01', 'se02', 'se03', 'se04'],
170
+ components: {
171
+ se01: { target: 'SE01', url: 'https://example.com/se01.bin', version: [2, 0, 0] },
172
+ se02: { target: 'SE02', url: 'https://example.com/se02.bin', version: [3, 0, 0] },
173
+ se03: { target: 'SE03', url: 'https://example.com/se03.bin', version: [2, 0, 0] },
174
+ se04: { target: 'SE04', url: 'https://example.com/se04.bin', version: [2, 0, 0] },
175
+ },
176
+ };
177
+
178
+ const result = buildProtocolV2FirmwareRelease({
179
+ currentVersions,
180
+ firmwareType: EFirmwareType.Universal,
181
+ release: neoRelease,
182
+ deviceType: 'neo',
183
+ });
184
+
185
+ expect(result.targetsToUpdate).toEqual(['se01', 'se02']);
186
+ expect(result.components).toEqual(
187
+ expect.arrayContaining([
188
+ expect.objectContaining({ configKey: 'se03', status: 'unsupported', updateTarget: null }),
189
+ expect.objectContaining({ configKey: 'se04', status: 'unsupported', updateTarget: null }),
190
+ ])
191
+ );
192
+ });
193
+
166
194
  test('returns an unavailable plan when no Pro2 release is configured', () => {
167
195
  expect(
168
196
  buildProtocolV2FirmwareRelease({
@@ -1,61 +1,19 @@
1
- import DataManager from '../src/data-manager/DataManager';
2
1
  import { parseConnectSettings } from '../src/data-manager/connectSettings';
3
2
 
4
- import type { RemoteConfigResponse } from '../src/types';
5
-
6
- jest.mock('axios', () => ({
7
- get: jest.fn(),
8
- }));
9
-
10
3
  jest.mock('../src/data/config', () => ({
11
4
  getSDKVersion: jest.fn(() => '1.0.0'),
12
5
  DEFAULT_DOMAIN: 'https://jssdk.onekey.so/1.0.0/',
13
6
  }));
14
7
 
15
- const mockAxiosGet: jest.Mock = jest.requireMock('axios').get;
16
-
17
8
  describe('parseConnectSettings', () => {
18
- const preloadedConfig = {
19
- bridge: {},
20
- classic: { firmware: [], ble: [] },
21
- classic1s: { firmware: [], ble: [] },
22
- classicpure: { firmware: [], ble: [] },
23
- mini: { firmware: [], ble: [] },
24
- touch: { firmware: [], ble: [] },
25
- pro: { firmware: [], ble: [] },
26
- pro2: { firmware: [], ble: [] },
27
- } as unknown as RemoteConfigResponse;
28
-
29
- it('keeps a serializable preloaded config in parsed settings', () => {
30
- const settings = parseConnectSettings({
31
- firmwareManifestMode: 'sdk-managed',
32
- preloadedConfig,
33
- });
34
-
35
- expect(settings.firmwareManifestMode).toBe('sdk-managed');
36
- expect(settings.preloadedConfig).toBe(preloadedConfig);
37
- });
38
-
39
- it('uses the preloaded config before the SDK network client', async () => {
40
- const settings = parseConnectSettings({
41
- firmwareManifestMode: 'sdk-managed',
42
- preloadedConfig,
43
- });
44
-
45
- await DataManager.load(settings);
46
-
47
- expect(mockAxiosGet).not.toHaveBeenCalled();
48
- expect(DataManager.deviceMap.classic).toEqual({ firmware: [], ble: [] });
49
- });
9
+ it('keeps custom configFetcher in parsed settings', () => {
10
+ const configFetcher = jest.fn();
50
11
 
51
- it('fails closed without a preloaded config in external-only mode', async () => {
52
12
  const settings = parseConnectSettings({
53
- firmwareManifestMode: 'external-only',
13
+ fetchConfig: true,
14
+ configFetcher,
54
15
  });
55
16
 
56
- await expect(DataManager.load(settings)).rejects.toThrow(
57
- 'External firmware config snapshot is required'
58
- );
59
- expect(mockAxiosGet).not.toHaveBeenCalled();
17
+ expect(settings.configFetcher).toBe(configFetcher);
60
18
  });
61
19
  });
@@ -1,8 +1,8 @@
1
- import { EDeviceType, EFirmwareType, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
1
+ import { EDeviceType, EFirmwareType, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
2
 
3
3
  import FirmwareUpdateV2 from '../../src/api/FirmwareUpdateV2';
4
4
  import { getBinary } from '../../src/api/firmware/getBinary';
5
- import { uploadFirmwareFromSource } from '../../src/api/firmware/uploadFirmware';
5
+ import { uploadFirmware } from '../../src/api/firmware/uploadFirmware';
6
6
  import * as utils from '../../src/utils';
7
7
 
8
8
  jest.mock('../../src/data/config', () => ({
@@ -18,8 +18,7 @@ jest.mock('../../src/api/firmware/getBinary', () => ({
18
18
 
19
19
  jest.mock('../../src/api/firmware/uploadFirmware', () => ({
20
20
  updateResources: jest.fn(),
21
- updateResourcesFromSources: jest.fn(),
22
- uploadFirmwareFromSource: jest.fn(),
21
+ uploadFirmware: jest.fn(),
23
22
  }));
24
23
 
25
24
  jest.mock('../../src/device/DevicePool', () => ({
@@ -30,9 +29,7 @@ jest.mock('../../src/device/DevicePool', () => ({
30
29
  }));
31
30
 
32
31
  const mockGetBinary = getBinary as jest.MockedFunction<typeof getBinary>;
33
- const mockUploadFirmwareFromSource = uploadFirmwareFromSource as jest.MockedFunction<
34
- typeof uploadFirmwareFromSource
35
- >;
32
+ const mockUploadFirmware = uploadFirmware as jest.MockedFunction<typeof uploadFirmware>;
36
33
 
37
34
  type DeviceType = 'CLASSIC1S' | 'PURE';
38
35
 
@@ -178,26 +175,7 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
178
175
  expect(mockGetBinary).toHaveBeenCalledTimes(1);
179
176
  expectNoFirmwareMutationCalls(typedCall);
180
177
  expect(acquire).not.toHaveBeenCalled();
181
- expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
182
- });
183
-
184
- it('preserves structured preparation errors before any firmware mutation', async () => {
185
- const preparationError = ERRORS.TypedError(
186
- HardwareErrorCode.RuntimeError,
187
- 'Firmware must be prepared by the external firmware host',
188
- {
189
- firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
190
- artifactName: 'firmware',
191
- }
192
- );
193
- mockGetBinary.mockRejectedValue(preparationError);
194
- const { method, typedCall, acquire } = createMethod();
195
-
196
- await expect(method.run()).rejects.toBe(preparationError);
197
-
198
- expectNoFirmwareMutationCalls(typedCall);
199
- expect(acquire).not.toHaveBeenCalled();
200
- expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
178
+ expect(mockUploadFirmware).not.toHaveBeenCalled();
201
179
  });
202
180
 
203
181
  it.each([
@@ -238,11 +216,9 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
238
216
  binary: firmwareBinary,
239
217
  } as Awaited<ReturnType<typeof getBinary>>);
240
218
  });
241
- mockUploadFirmwareFromSource.mockImplementation(() => {
219
+ mockUploadFirmware.mockImplementation(() => {
242
220
  callOrder.push('upload');
243
- return Promise.resolve(
244
- expectedResponse as Awaited<ReturnType<typeof uploadFirmwareFromSource>>
245
- );
221
+ return Promise.resolve(expectedResponse as Awaited<ReturnType<typeof uploadFirmware>>);
246
222
  });
247
223
  const { method, typedCall } = createMethod({
248
224
  updateType,
@@ -272,15 +248,15 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
272
248
  },
273
249
  })
274
250
  );
275
- expect(mockUploadFirmwareFromSource).toHaveBeenCalledWith(
251
+ expect(mockUploadFirmware).toHaveBeenCalledWith(
276
252
  updateType,
277
253
  expect.any(Function),
278
254
  expect.any(Function),
279
255
  method.device,
280
- expect.objectContaining({
281
- size: firmwareBinary.byteLength,
282
- }),
283
- true,
256
+ {
257
+ payload: firmwareBinary,
258
+ rebootOnSuccess: true,
259
+ },
284
260
  isUpdateBootloader
285
261
  );
286
262
  }
@@ -295,11 +271,11 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
295
271
  binary: firmwareBinary,
296
272
  } as Awaited<ReturnType<typeof getBinary>>);
297
273
  });
298
- mockUploadFirmwareFromSource.mockImplementation(() => {
274
+ mockUploadFirmware.mockImplementation(() => {
299
275
  callOrder.push('upload');
300
276
  return Promise.resolve({
301
277
  success: true,
302
- } as Awaited<ReturnType<typeof uploadFirmwareFromSource>>);
278
+ } as Awaited<ReturnType<typeof uploadFirmware>>);
303
279
  });
304
280
  const { method, typedCall, acquire } = createMethod({
305
281
  bootloaderMode: true,
@@ -324,9 +300,9 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
324
300
  resolveDownload = resolve;
325
301
  })
326
302
  );
327
- mockUploadFirmwareFromSource.mockResolvedValue({
303
+ mockUploadFirmware.mockResolvedValue({
328
304
  success: true,
329
- } as Awaited<ReturnType<typeof uploadFirmwareFromSource>>);
305
+ } as Awaited<ReturnType<typeof uploadFirmware>>);
330
306
  const { method, typedCall } = createMethod();
331
307
 
332
308
  const runPromise = method.run();
@@ -357,7 +333,7 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
357
333
 
358
334
  expectNoFirmwareMutationCalls(typedCall);
359
335
  expect(acquire).not.toHaveBeenCalled();
360
- expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
336
+ expect(mockUploadFirmware).not.toHaveBeenCalled();
361
337
  });
362
338
 
363
339
  it.each([
@@ -366,23 +342,23 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
366
342
  ])(
367
343
  'keeps the non-empty %s binary overload and never downloads it again',
368
344
  async (_kind, binary) => {
369
- mockUploadFirmwareFromSource.mockResolvedValue({
345
+ mockUploadFirmware.mockResolvedValue({
370
346
  success: true,
371
- } as Awaited<ReturnType<typeof uploadFirmwareFromSource>>);
347
+ } as Awaited<ReturnType<typeof uploadFirmware>>);
372
348
  const { method } = createMethod({ binary });
373
349
 
374
350
  await method.run();
375
351
 
376
352
  expect(mockGetBinary).not.toHaveBeenCalled();
377
- expect(mockUploadFirmwareFromSource).toHaveBeenCalledWith(
353
+ expect(mockUploadFirmware).toHaveBeenCalledWith(
378
354
  'firmware',
379
355
  expect.any(Function),
380
356
  expect.any(Function),
381
357
  method.device,
382
- expect.objectContaining({
383
- size: binary.byteLength,
384
- }),
385
- true,
358
+ {
359
+ payload: binary,
360
+ rebootOnSuccess: true,
361
+ },
386
362
  undefined
387
363
  );
388
364
  }
@@ -393,21 +369,17 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
393
369
  ['DataView', new DataView(new Uint8Array([9, 3, 4, 9]).buffer, 1, 2), [3, 4]],
394
370
  ['custom Buffer', createCustomBuffer(4), [1, 2, 3, 4]],
395
371
  ])('normalizes a non-empty %s before rebooting', async (_kind, binary, expectedBytes) => {
396
- let uploadedBytes: number[] = [];
397
- mockUploadFirmwareFromSource.mockImplementation(
398
- async (_updateType, _typedCall, _postMessage, _device, source) => {
399
- uploadedBytes = Array.from(new Uint8Array(await source.readAt(0, source.size)));
400
- return {
401
- success: true,
402
- } as Awaited<ReturnType<typeof uploadFirmwareFromSource>>;
403
- }
404
- );
372
+ mockUploadFirmware.mockResolvedValue({
373
+ success: true,
374
+ } as Awaited<ReturnType<typeof uploadFirmware>>);
405
375
  const { method } = createMethod({ binary });
406
376
 
407
377
  await method.run();
408
378
 
409
379
  expect(mockGetBinary).not.toHaveBeenCalled();
410
- expect(uploadedBytes).toEqual(expectedBytes);
380
+ const normalizedBinary = mockUploadFirmware.mock.calls[0][4].payload;
381
+ expect(normalizedBinary).toBeInstanceOf(ArrayBuffer);
382
+ expect(Array.from(new Uint8Array(normalizedBinary))).toEqual(expectedBytes);
411
383
  });
412
384
 
413
385
  it.each([
@@ -425,6 +397,6 @@ describe('FirmwareUpdateV2 download-before-reboot safety', () => {
425
397
  expect(mockGetBinary).not.toHaveBeenCalled();
426
398
  expectNoFirmwareMutationCalls(typedCall);
427
399
  expect(acquire).not.toHaveBeenCalled();
428
- expect(mockUploadFirmwareFromSource).not.toHaveBeenCalled();
400
+ expect(mockUploadFirmware).not.toHaveBeenCalled();
429
401
  });
430
402
  });
@@ -1,5 +1,10 @@
1
+ import { EDeviceType } from '@onekeyfe/hd-shared';
2
+
1
3
  import { ProtocolV2FirmwareTargetType } from '../src/protocols/protocol-v2/firmware';
2
- import { isProtocolV2FirmwareFingerprintValid } from '../src/api/FirmwareUpdateV4';
4
+ import {
5
+ assertProtocolV2FirmwareTargetsSupported,
6
+ isProtocolV2FirmwareFingerprintValid,
7
+ } from '../src/api/FirmwareUpdateV4';
3
8
 
4
9
  jest.mock('../src/data/config', () => ({
5
10
  DEFAULT_DOMAIN: 'https://example.com/',
@@ -34,4 +39,31 @@ describe('Protocol V2 firmware target contract', () => {
34
39
  ).toBe(true);
35
40
  expect(isProtocolV2FirmwareFingerprintValid(binary, '00'.repeat(32))).toBe(false);
36
41
  });
42
+
43
+ test('allows only SE01 and SE02 firmware targets on Neo', () => {
44
+ expect(() =>
45
+ assertProtocolV2FirmwareTargetsSupported(EDeviceType.Neo, {
46
+ platform: 'web',
47
+ targetsToUpdate: ['se01', 'se02'],
48
+ })
49
+ ).not.toThrow();
50
+
51
+ expect(() =>
52
+ assertProtocolV2FirmwareTargetsSupported(EDeviceType.Neo, {
53
+ platform: 'web',
54
+ targetsToUpdate: ['se03'],
55
+ se04Binary: new ArrayBuffer(1),
56
+ })
57
+ ).toThrow('Neo only supports SE01 and SE02; unsupported firmware targets: se03, se04');
58
+ });
59
+
60
+ test('keeps all four SE firmware targets available on Pro2', () => {
61
+ expect(() =>
62
+ assertProtocolV2FirmwareTargetsSupported(EDeviceType.Pro2, {
63
+ platform: 'web',
64
+ targetsToUpdate: ['se03'],
65
+ se04Binary: new ArrayBuffer(1),
66
+ })
67
+ ).not.toThrow();
68
+ });
37
69
  });
@@ -95,7 +95,7 @@ describe('Pro2 resource configuration', () => {
95
95
  DataManager.lastCheckTimestamp = 0;
96
96
  });
97
97
 
98
- test('accepts exactly six resources and normalizes their deterministic order', () => {
98
+ test('accepts exactly seven resources and normalizes their deterministic order', () => {
99
99
  const parsed = parseProtocolV2Resources({
100
100
  stable: [...resources].reverse(),
101
101
  boot: bootResources,
@@ -106,15 +106,18 @@ describe('Pro2 resource configuration', () => {
106
106
  expect(PROTOCOL_V2_RESOURCE_DEVICE_PATHS.translations).toBe(
107
107
  'vol0:/bundles/translations/translations.okpkg'
108
108
  );
109
+ expect(PROTOCOL_V2_RESOURCE_DEVICE_PATHS.firmware_logo).toBe(
110
+ 'vol0:/bundles/firmware_logo.okpkg'
111
+ );
109
112
  });
110
113
 
111
114
  test('rejects incomplete, duplicate, or malformed stable sets', () => {
112
115
  expect(() => parseProtocolV2Resources({ stable: resources.slice(1) })).toThrow(
113
- 'six unique resource types'
116
+ '7 unique resource types'
114
117
  );
115
118
  expect(() =>
116
- parseProtocolV2Resources({ stable: [...resources.slice(0, 5), resources[0]] })
117
- ).toThrow('six unique resource types');
119
+ parseProtocolV2Resources({ stable: [...resources.slice(0, 6), resources[0]] })
120
+ ).toThrow('7 unique resource types');
118
121
  expect(() =>
119
122
  parseProtocolV2Resources({
120
123
  stable: resources.map((resource, index) =>
@@ -224,7 +227,7 @@ describe('Pro2 resource configuration', () => {
224
227
  );
225
228
  expect(typedCall.mock.calls.some(call => call[0] === 'ResourceInventoryGet')).toBe(false);
226
229
  expect(typedCall.mock.calls.filter(call => call[0] === 'FilesystemPathInfoQuery')).toHaveLength(
227
- 6
230
+ 7
228
231
  );
229
232
  expect(typedCall.mock.calls.some(call => call[0] === 'FilesystemFileRead')).toBe(true);
230
233
  });
@@ -255,7 +258,7 @@ describe('Pro2 resource configuration', () => {
255
258
  });
256
259
  expect(
257
260
  buildProtocolV2ResourceUpdatePlan({ resources, mode: 'bootloader-recovery' }).resources
258
- ).toHaveLength(6);
261
+ ).toHaveLength(7);
259
262
  });
260
263
 
261
264
  test('uses a filesystem inventory for incremental recovery mode updates', () => {