@onekeyfe/hd-core 1.2.0-alpha.82 → 1.2.0-alpha.84

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.
@@ -333,6 +333,15 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
333
333
  resourceArchive: resourceSource,
334
334
  resourcePreparationRequired: true,
335
335
  targetsToUpdate: ['boot', 'app_v1', 'resource'],
336
+ firmwareUpdatePlan: {
337
+ executor: 'v4',
338
+ platform: 'web',
339
+ artifacts: [
340
+ { artifactId: 'component:boot', target: 'boot' },
341
+ { artifactId: 'component:app_v1', target: 'app_v1' },
342
+ ],
343
+ targetsToUpdate: ['boot', 'app_v1'],
344
+ },
336
345
  firmware: {
337
346
  status: 'required',
338
347
  },
@@ -344,6 +353,260 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
344
353
  expect(method.getSupportedProtocols()).toEqual(['V1', 'V2']);
345
354
  });
346
355
 
356
+ test('preserves platform and forced firmware targets in the Protocol V2 prepared plan', async () => {
357
+ const method = new CheckAllFirmwareRelease({
358
+ id: 1,
359
+ payload: {
360
+ method: 'checkAllFirmwareRelease',
361
+ firmwareType: EFirmwareType.Universal,
362
+ platform: 'native',
363
+ forceUpdateTargets: ['firmware'],
364
+ },
365
+ });
366
+ method.init();
367
+ method.device = {
368
+ isProtocolV2: () => true,
369
+ features: {
370
+ deviceType: 'pro2',
371
+ serialNo: 'pro2-device-id',
372
+ firmwareVersion: '1.0.0',
373
+ },
374
+ getDeviceState: jest.fn().mockResolvedValue({
375
+ identity: { deviceType: 'pro2', firmwareType: EFirmwareType.Universal },
376
+ status: { mode: 'normal' },
377
+ versions: currentVersions,
378
+ }),
379
+ } as unknown as CheckAllFirmwareRelease['device'];
380
+ jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(release);
381
+ jest.spyOn(DataManager, 'getProtocolV2ResourceSource').mockReturnValue(resourceSource);
382
+
383
+ await expect(method.run()).resolves.toMatchObject({
384
+ targetsToUpdate: ['boot', 'app_v1', 'se02', 'se03', 'resource'],
385
+ firmwareUpdatePlan: {
386
+ executor: 'v4',
387
+ deviceIdentity: 'pro2-device-id',
388
+ platform: 'native',
389
+ artifacts: [
390
+ { artifactId: 'component:boot', target: 'boot' },
391
+ { artifactId: 'component:app_v1', target: 'app_v1' },
392
+ { artifactId: 'component:se02', target: 'se02' },
393
+ { artifactId: 'component:se03', target: 'se03' },
394
+ ],
395
+ targetsToUpdate: ['boot', 'app_v1', 'se02', 'se03'],
396
+ },
397
+ });
398
+ });
399
+
400
+ test('includes exact Protocol V2 developer force targets in the prepared plan', async () => {
401
+ const currentRelease: IFirmwareReleaseInfo = {
402
+ ...release,
403
+ required: false,
404
+ version: [1, 0, 0],
405
+ installOrder: ['applicationP1', 'coprocessor'],
406
+ components: {
407
+ applicationP1: {
408
+ target: 'APPLICATION_P1',
409
+ url: 'https://example.com/application-p1.okpkg',
410
+ version: [1, 0, 0],
411
+ },
412
+ coprocessor: {
413
+ target: 'COPROCESSOR',
414
+ url: 'https://example.com/coprocessor.okpkg',
415
+ version: [1, 0, 0],
416
+ },
417
+ },
418
+ };
419
+ const method = new CheckAllFirmwareRelease({
420
+ id: 1,
421
+ payload: {
422
+ method: 'checkAllFirmwareRelease',
423
+ platform: 'desktop',
424
+ protocolV2ForceUpdateTargets: ['app_v1', 'coprocessor'],
425
+ },
426
+ });
427
+ method.init();
428
+ method.device = {
429
+ isProtocolV2: () => true,
430
+ features: {
431
+ deviceType: 'pro2',
432
+ serialNo: 'pro2-device-id',
433
+ firmwareVersion: '1.0.0',
434
+ },
435
+ getDeviceState: jest.fn().mockResolvedValue({
436
+ identity: { deviceType: 'pro2', firmwareType: EFirmwareType.Universal },
437
+ status: { mode: 'normal' },
438
+ versions: { ...currentVersions, applicationP1: '1.0.0' },
439
+ }),
440
+ } as unknown as CheckAllFirmwareRelease['device'];
441
+ jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(currentRelease);
442
+ jest.spyOn(DataManager, 'getProtocolV2ResourceSource').mockReturnValue(resourceSource);
443
+
444
+ await expect(method.run()).resolves.toMatchObject({
445
+ targetsToUpdate: ['app_v1', 'coprocessor', 'resource'],
446
+ firmwareUpdatePlan: {
447
+ executor: 'v4',
448
+ platform: 'desktop',
449
+ artifacts: [
450
+ { artifactId: 'component:app_v1', target: 'app_v1' },
451
+ { artifactId: 'component:coprocessor', target: 'coprocessor' },
452
+ ],
453
+ targetsToUpdate: ['app_v1', 'coprocessor'],
454
+ },
455
+ });
456
+ });
457
+
458
+ test('keeps exact force targets but omits a Desktop Plan without device identity', async () => {
459
+ const currentRelease: IFirmwareReleaseInfo = {
460
+ ...release,
461
+ required: false,
462
+ version: [1, 0, 0],
463
+ installOrder: ['applicationP1'],
464
+ components: {
465
+ applicationP1: {
466
+ target: 'APPLICATION_P1',
467
+ url: 'https://example.com/application-p1.okpkg',
468
+ version: [1, 0, 0],
469
+ },
470
+ },
471
+ };
472
+ const method = new CheckAllFirmwareRelease({
473
+ id: 1,
474
+ payload: {
475
+ method: 'checkAllFirmwareRelease',
476
+ platform: 'desktop',
477
+ protocolV2ForceUpdateTargets: ['app_v1'],
478
+ },
479
+ });
480
+ method.init();
481
+ method.device = {
482
+ isProtocolV2: () => true,
483
+ features: { deviceType: 'pro2', firmwareVersion: '1.0.0' },
484
+ getDeviceState: jest.fn().mockResolvedValue({
485
+ identity: { deviceType: 'pro2', firmwareType: EFirmwareType.Universal },
486
+ status: { mode: 'normal' },
487
+ versions: { ...currentVersions, applicationP1: '1.0.0' },
488
+ }),
489
+ } as unknown as CheckAllFirmwareRelease['device'];
490
+ jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(currentRelease);
491
+ jest.spyOn(DataManager, 'getProtocolV2ResourceSource').mockReturnValue(resourceSource);
492
+
493
+ await expect(method.run()).resolves.toMatchObject({
494
+ targetsToUpdate: ['app_v1', 'resource'],
495
+ firmwareUpdatePlan: undefined,
496
+ });
497
+ });
498
+
499
+ test('rejects Neo-only unsupported exact secure-element targets', async () => {
500
+ const neoRelease: IFirmwareReleaseInfo = {
501
+ ...release,
502
+ required: false,
503
+ installOrder: ['se03'],
504
+ components: {
505
+ se03: {
506
+ target: 'SE03',
507
+ url: 'https://example.com/se03.okpkg',
508
+ version: [1, 0, 0],
509
+ },
510
+ },
511
+ };
512
+ const method = new CheckAllFirmwareRelease({
513
+ id: 1,
514
+ payload: {
515
+ method: 'checkAllFirmwareRelease',
516
+ protocolV2ForceUpdateTargets: ['se03'],
517
+ },
518
+ });
519
+ method.init();
520
+ method.device = {
521
+ isProtocolV2: () => true,
522
+ features: { deviceType: 'neo', firmwareVersion: '1.0.0' },
523
+ getDeviceState: jest.fn().mockResolvedValue({
524
+ identity: { deviceType: 'neo', firmwareType: EFirmwareType.Universal },
525
+ status: { mode: 'normal' },
526
+ versions: currentVersions,
527
+ }),
528
+ } as unknown as CheckAllFirmwareRelease['device'];
529
+ jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(neoRelease);
530
+ jest.spyOn(DataManager, 'getProtocolV2ResourceSource').mockReturnValue(resourceSource);
531
+
532
+ await expect(method.run()).rejects.toMatchObject({
533
+ params: { firmwareUpdateCode: 'FirmwarePlanInvalid' },
534
+ });
535
+ });
536
+
537
+ test('builds a V4 plan for Neo and excludes unsupported secure elements when forced', async () => {
538
+ const neoRelease: IFirmwareReleaseInfo = {
539
+ ...release,
540
+ installOrder: ['se01', 'se02', 'se03', 'se04'],
541
+ components: {
542
+ se01: { target: 'SE01', url: 'https://example.com/se01.bin', version: [1, 0, 0] },
543
+ se02: { target: 'SE02', url: 'https://example.com/se02.bin', version: [2, 0, 0] },
544
+ se03: { target: 'SE03', url: 'https://example.com/se03.bin', version: [1, 0, 0] },
545
+ se04: { target: 'SE04', url: 'https://example.com/se04.bin', version: [1, 0, 0] },
546
+ },
547
+ };
548
+ const method = new CheckAllFirmwareRelease({
549
+ id: 1,
550
+ payload: {
551
+ method: 'checkAllFirmwareRelease',
552
+ platform: 'native',
553
+ forceUpdateTargets: ['firmware'],
554
+ },
555
+ });
556
+ method.init();
557
+ method.device = {
558
+ isProtocolV2: () => true,
559
+ features: {
560
+ deviceType: 'neo',
561
+ serialNo: 'neo-device-id',
562
+ firmwareVersion: '1.0.0',
563
+ },
564
+ getDeviceState: jest.fn().mockResolvedValue({
565
+ identity: { deviceType: 'neo', firmwareType: EFirmwareType.Universal },
566
+ status: { mode: 'normal' },
567
+ versions: currentVersions,
568
+ }),
569
+ } as unknown as CheckAllFirmwareRelease['device'];
570
+ jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(neoRelease);
571
+ jest.spyOn(DataManager, 'getProtocolV2ResourceSource').mockReturnValue(resourceSource);
572
+
573
+ await expect(method.run()).resolves.toMatchObject({
574
+ targetsToUpdate: ['se01', 'se02', 'resource'],
575
+ firmwareUpdatePlan: {
576
+ executor: 'v4',
577
+ deviceModel: 'neo',
578
+ platform: 'native',
579
+ targetsToUpdate: ['se01', 'se02'],
580
+ },
581
+ });
582
+ });
583
+
584
+ test('rejects a forced Protocol V2 resource target without a configured archive', async () => {
585
+ const method = new CheckAllFirmwareRelease({
586
+ id: 1,
587
+ payload: {
588
+ method: 'checkAllFirmwareRelease',
589
+ forceUpdateTargets: ['resource'],
590
+ },
591
+ });
592
+ method.init();
593
+ method.device = {
594
+ isProtocolV2: () => true,
595
+ features: { deviceType: 'pro2', firmwareVersion: '1.0.0' },
596
+ getDeviceState: jest.fn().mockResolvedValue({
597
+ identity: { deviceType: 'pro2', firmwareType: EFirmwareType.Universal },
598
+ status: { mode: 'normal' },
599
+ versions: currentVersions,
600
+ }),
601
+ } as unknown as CheckAllFirmwareRelease['device'];
602
+ jest.spyOn(DataManager, 'getFirmwareLatestRelease').mockReturnValue(release);
603
+ jest.spyOn(DataManager, 'getProtocolV2ResourceSource').mockReturnValue(undefined);
604
+
605
+ await expect(method.run()).rejects.toMatchObject({
606
+ params: { firmwareUpdateCode: 'FirmwarePlanInvalid' },
607
+ });
608
+ });
609
+
347
610
  test('requests and compares firmware hashes only when explicitly enabled', async () => {
348
611
  const packageSet: IFirmwareReleaseInfo = {
349
612
  ...release,
@@ -467,6 +730,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
467
730
  resourceStatus: 'unknown',
468
731
  resourcePreparationRequired: true,
469
732
  targetsToUpdate: ['resource'],
733
+ firmwareUpdatePlan: undefined,
470
734
  });
471
735
  });
472
736
 
@@ -477,6 +741,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
477
741
  await api.checkAllFirmwareRelease('pro2-connect-id', {
478
742
  checkFirmwareHash: true,
479
743
  firmwareType: EFirmwareType.Universal,
744
+ protocolV2ForceUpdateTargets: ['app_v1'],
480
745
  retryCount: 0,
481
746
  });
482
747
 
@@ -484,6 +749,7 @@ describe('checkAllFirmwareRelease Protocol V2 support', () => {
484
749
  connectId: 'pro2-connect-id',
485
750
  checkFirmwareHash: true,
486
751
  firmwareType: EFirmwareType.Universal,
752
+ protocolV2ForceUpdateTargets: ['app_v1'],
487
753
  retryCount: 0,
488
754
  method: 'checkAllFirmwareRelease',
489
755
  });
@@ -22,6 +22,10 @@ const release: IFirmwareReleaseInfo = {
22
22
  'zh-CN': '更新',
23
23
  'en-US': 'Update',
24
24
  },
25
+ bootloaderChangelog: {
26
+ 'zh-CN': '旧版 Bootloader 更新',
27
+ 'en-US': 'Legacy bootloader update',
28
+ },
25
29
  installOrder: ['bootloader', 'applicationP1', 'coprocessor'],
26
30
  components: {
27
31
  bootloader: {
@@ -127,6 +131,7 @@ describe.each(['pro2', 'neo'] as const)('Protocol V2 release checks for %s', dev
127
131
  await expect(bootloaderMethod.run()).resolves.toMatchObject({
128
132
  status: 'outdated',
129
133
  shouldUpdate: true,
134
+ changelog: [release.changelog],
130
135
  release: {
131
136
  protocol: 'V2',
132
137
  configKey: 'bootloader',
@@ -134,6 +139,7 @@ describe.each(['pro2', 'neo'] as const)('Protocol V2 release checks for %s', dev
134
139
  target: 'BOOTLOADER',
135
140
  url: 'https://example.com/bootloader.okpkg',
136
141
  version: [2, 0, 0],
142
+ changelog: release.changelog,
137
143
  },
138
144
  });
139
145
  await expect(allMethod.run()).resolves.toMatchObject({
@@ -2778,9 +2778,12 @@ describe('Protocol V2 feature adapter', () => {
2778
2778
  expect(checkedTypes).toEqual(['pro2', 'model_pro2']);
2779
2779
  });
2780
2780
 
2781
- test('uses firmware-v1 as the Pro2 remote firmware config field', () => {
2781
+ test.each([
2782
+ ['Pro2', DeviceType.PRO2],
2783
+ ['Neo', DeviceType.NEO],
2784
+ ] as const)('uses firmware-v1 as the %s remote firmware config field', (_name, deviceType) => {
2782
2785
  const features = normalizeProtocolV2Features({ ...descriptor, protocolType: 'V2' } as any, {
2783
- hw: { Device_type: DeviceType.PRO2 },
2786
+ hw: { Device_type: deviceType },
2784
2787
  });
2785
2788
 
2786
2789
  expect(
@@ -1 +1 @@
1
- {"version":3,"file":"CheckAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckAllFirmwareRelease.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AA8B1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EACV,kBAAkB,EAElB,kCAAkC,EAClC,+BAA+B,EAChC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EAGrB,MAAM,UAAU,CAAC;AAgIlB,MAAM,MAAM,6BAA6B,GAAG;IAC1C,YAAY,EAAE,aAAa,CAAC;IAC5B,MAAM,EAAE,+BAA+B,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,mBAAmB,CAAC;IACrC,UAAU,EAAE,kCAAkC,EAAE,CAAC;IACjD,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF,wBAAgB,8BAA8B,CAAC,EAC7C,eAAe,EACf,mBAAwB,EACxB,iBAAyB,EACzB,mBAAwB,EACxB,YAAY,EACZ,OAAO,EACP,UAAU,GACX,EAAE;IACD,eAAe,EAAE,mBAAmB,CAAC;IACrC,mBAAmB,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC9D,YAAY,EAAE,aAAa,CAAC;IAC5B,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC7B,GAAG,6BAA6B,CAiFhC;AAID,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,UAAU;IAC7D,qBAAqB;IAIrB,IAAI;IAME,GAAG;YAuFK,aAAa;CA+D5B"}
1
+ {"version":3,"file":"CheckAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../src/api/CheckAllFirmwareRelease.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAiC1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EACV,kBAAkB,EAElB,kCAAkC,EAClC,+BAA+B,EAChC,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,KAAK,EACV,oBAAoB,EACpB,mBAAmB,EACnB,oBAAoB,EAGrB,MAAM,UAAU,CAAC;AAgIlB,MAAM,MAAM,6BAA6B,GAAG;IAC1C,YAAY,EAAE,aAAa,CAAC;IAC5B,MAAM,EAAE,+BAA+B,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,mBAAmB,CAAC;IACrC,UAAU,EAAE,kCAAkC,EAAE,CAAC;IACjD,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF,wBAAgB,8BAA8B,CAAC,EAC7C,eAAe,EACf,mBAAwB,EACxB,iBAAyB,EACzB,mBAAwB,EACxB,YAAY,EACZ,OAAO,EACP,UAAU,GACX,EAAE;IACD,eAAe,EAAE,mBAAmB,CAAC;IACrC,mBAAmB,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACpD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mBAAmB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC9D,YAAY,EAAE,aAAa,CAAC;IAC5B,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC7B,GAAG,6BAA6B,CAiFhC;AAID,MAAM,CAAC,OAAO,OAAO,uBAAwB,SAAQ,UAAU;IAC7D,qBAAqB;IAIrB,IAAI;IAME,GAAG;YAuFK,aAAa;CAmI5B"}
@@ -1,7 +1,30 @@
1
1
  import { EFirmwareType } from '@onekeyfe/hd-shared';
2
+ import type { FirmwareUpdateV4Target } from '../../types/api/firmwareUpdate';
2
3
  import type { FirmwareUpdatePlan, FirmwareUpdatePlanForceTarget, FirmwareUpdatePlanTarget } from '../../types/api/firmwareUpdatePlan';
3
4
  import type { Features } from '../../types';
4
5
  type FirmwareUpdatePlatform = 'native' | 'desktop' | 'ext' | 'web' | 'web-embed';
6
+ type ReleaseRecord = {
7
+ url?: unknown;
8
+ webUpdate?: unknown;
9
+ resource?: unknown;
10
+ fullResource?: unknown;
11
+ fullResourceRange?: unknown;
12
+ bootloaderResource?: unknown;
13
+ version?: unknown;
14
+ components?: unknown;
15
+ installOrder?: unknown;
16
+ resourceBundles?: unknown;
17
+ fingerprint?: unknown;
18
+ fingerprintWeb?: unknown;
19
+ expectedSize?: unknown;
20
+ resourceFingerprint?: unknown;
21
+ resourceExpectedSize?: unknown;
22
+ fullResourceFingerprint?: unknown;
23
+ fullResourceExpectedSize?: unknown;
24
+ bootloaderFingerprint?: unknown;
25
+ bootloaderExpectedSize?: unknown;
26
+ bootloaderVersion?: unknown;
27
+ };
5
28
  type ReleaseSelection = {
6
29
  shouldUpdate?: boolean;
7
30
  status?: unknown;
@@ -9,9 +32,19 @@ type ReleaseSelection = {
9
32
  };
10
33
  export declare const digestFirmwareUpdateContract: (value: unknown) => string;
11
34
  export declare const validateFirmwareUpdatePlanForceTargets: (value: unknown) => FirmwareUpdatePlanForceTarget[];
35
+ export declare const validateProtocolV2FirmwareUpdateTargets: (value: unknown) => FirmwareUpdateV4Target[];
12
36
  export declare const FIRMWARE_UPDATE_PLAN_TARGETS: Set<FirmwareUpdatePlanTarget>;
13
37
  export declare const FIRMWARE_UPDATE_PLAN_ROLES: Set<string>;
14
38
  export declare const assertFirmwareUpdatePlan: (value: unknown) => FirmwareUpdatePlan;
39
+ export declare const buildProtocolV2FirmwareUpdatePlan: ({ features, firmwareType, platform, release, targetsToUpdate, forceUpdateTargets, resourceArchiveAvailable, }: {
40
+ features: Features;
41
+ firmwareType: EFirmwareType;
42
+ platform: FirmwareUpdatePlatform;
43
+ release: ReleaseRecord | undefined;
44
+ targetsToUpdate: readonly FirmwareUpdateV4Target[];
45
+ forceUpdateTargets?: FirmwareUpdatePlanForceTarget[] | undefined;
46
+ resourceArchiveAvailable: boolean;
47
+ }) => FirmwareUpdatePlan;
15
48
  export declare const buildFirmwareUpdatePlan: ({ features, firmwareType, platform, firmware, ble, bootloader, forceUpdateTargets, }: {
16
49
  features: Features;
17
50
  firmwareType: EFirmwareType;
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwareUpdatePlan.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwareUpdatePlan.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAU5F,OAAO,KAAK,EACV,kBAAkB,EAElB,6BAA6B,EAC7B,wBAAwB,EACzB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,KAAK,sBAAsB,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,WAAW,CAAC;AAyBjF,KAAK,gBAAgB,GAAG;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AA0GF,eAAO,MAAM,4BAA4B,UAAW,OAAO,KAAG,MAG3D,CAAC;AAkBJ,eAAO,MAAM,sCAAsC,UAC1C,OAAO,KACb,6BAA6B,EAa/B,CAAC;AAuBF,eAAO,MAAM,4BAA4B,+BAavC,CAAC;AAEH,eAAO,MAAM,0BAA0B,aAOrC,CAAC;AAYH,eAAO,MAAM,wBAAwB,UAAW,OAAO,KAAG,kBAyHzD,CAAC;AA4NF,eAAO,MAAM,uBAAuB;cASxB,QAAQ;kBACJ,aAAa;cACjB,sBAAsB;cACtB,gBAAgB;SACrB,gBAAgB;;;MAGnB,kBAsKH,CAAC"}
1
+ {"version":3,"file":"FirmwareUpdatePlan.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwareUpdatePlan.ts"],"names":[],"mappings":"AAEA,OAAO,EAAe,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAU5F,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,KAAK,EACV,kBAAkB,EAElB,6BAA6B,EAC7B,wBAAwB,EACzB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C,KAAK,sBAAsB,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,WAAW,CAAC;AAEjF,KAAK,aAAa,GAAG;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,CAAC;AA+GF,eAAO,MAAM,4BAA4B,UAAW,OAAO,KAAG,MAG3D,CAAC;AAkBJ,eAAO,MAAM,sCAAsC,UAC1C,OAAO,KACb,6BAA6B,EAa/B,CAAC;AAEF,eAAO,MAAM,uCAAuC,UAC3C,OAAO,KACb,sBAAsB,EAaxB,CAAC;AAuBF,eAAO,MAAM,4BAA4B,+BAavC,CAAC;AAEH,eAAO,MAAM,0BAA0B,aAOrC,CAAC;AAYH,eAAO,MAAM,wBAAwB,UAAW,OAAO,KAAG,kBAyHzD,CAAC;AA0RF,eAAO,MAAM,iCAAiC;cASlC,QAAQ;kBACJ,aAAa;cACjB,sBAAsB;aACvB,aAAa,GAAG,SAAS;qBACjB,SAAS,sBAAsB,EAAE;;8BAExB,OAAO;MAC/B,kBA2CH,CAAC;AAEF,eAAO,MAAM,uBAAuB;cASxB,QAAQ;kBACJ,aAAa;cACjB,sBAAsB;cACtB,gBAAgB;SACrB,gBAAgB;;;MAGnB,kBAyIH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"protocolV2Release.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/protocolV2Release.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAI/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EACR,oBAAoB,EACpB,kCAAkC,EACnC,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,0BAA0B,EAC1B,8BAA8B,EAE/B,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAEhF,eAAO,MAAM,iCAAiC,EAAE,SAAS,kCAAkC,EAO1F,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,SAAS,kCAAkC,EAEhF,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,SAAS,kCAAkC,EAEvF,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG;IAC7C,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,GAAG;QACrC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC,GAAG;YACtD,UAAU,EAAE,WAAW,CAAC,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC;SAChD,CAAC;KACH,CAAC;IACF,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,aAAa,CAAC;IAC5B,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF,wBAAsB,oCAAoC,CAAC,EACzD,MAAM,EACN,YAAY,EAAE,iBAAiB,EAC/B,iBAAyB,EACzB,UAAU,GACX,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,gCAAgC,CAAC,CA4B5C;AAED,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,6BAA6B,EACnC,gBAAgB,EAAE,SAAS,kCAAkC,EAAE,GAC9D,6BAA6B,CAiC/B;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,IAAI,EACJ,KAAK,EACL,OAAO,GACR,EAAE;IACD,IAAI,EAAE,6BAA6B,CAAC;IACpC,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,0BAA0B,CAAC,SAAS,CAAC,CAAC;CAChD,GAAG,0BAA0B,CAQ7B;AAED,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,6BAA6B,EACnC,eAAe,EAAE,kCAAkC,GAClD,8BAA8B,GAAG,SAAS,CAmB5C"}
1
+ {"version":3,"file":"protocolV2Release.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/protocolV2Release.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAA6B,MAAM,qBAAqB,CAAC;AAI/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EACV,WAAW,EACX,QAAQ,EACR,oBAAoB,EACpB,kCAAkC,EACnC,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EACV,0BAA0B,EAC1B,8BAA8B,EAE/B,MAAM,yCAAyC,CAAC;AACjD,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,4BAA4B,CAAC;AAEhF,eAAO,MAAM,iCAAiC,EAAE,SAAS,kCAAkC,EAO1F,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,SAAS,kCAAkC,EAEhF,CAAC;AAEF,eAAO,MAAM,8BAA8B,EAAE,SAAS,kCAAkC,EAEvF,CAAC;AAEF,MAAM,MAAM,gCAAgC,GAAG;IAC7C,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC,GAAG;QACrC,QAAQ,EAAE,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,YAAY,CAAC,GAAG;YACtD,UAAU,EAAE,WAAW,CAAC,IAAI,GAAG,WAAW,CAAC,GAAG,CAAC;SAChD,CAAC;KACH,CAAC;IACF,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,aAAa,CAAC;IAC5B,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF,wBAAsB,oCAAoC,CAAC,EACzD,MAAM,EACN,YAAY,EAAE,iBAAiB,EAC/B,iBAAyB,EACzB,UAAU,GACX,EAAE;IACD,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,gCAAgC,CAAC,CA4B5C;AAED,wBAAgB,kCAAkC,CAChD,IAAI,EAAE,6BAA6B,EACnC,gBAAgB,EAAE,SAAS,kCAAkC,EAAE,GAC9D,6BAA6B,CAiC/B;AAED,wBAAgB,+BAA+B,CAAC,EAC9C,IAAI,EACJ,KAAK,EACL,OAAO,GACR,EAAE;IACD,IAAI,EAAE,6BAA6B,CAAC;IACpC,KAAK,EAAE,WAAW,CAAC;IACnB,OAAO,EAAE,0BAA0B,CAAC,SAAS,CAAC,CAAC;CAChD,GAAG,0BAA0B,CAU7B;AAED,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,6BAA6B,EACnC,eAAe,EAAE,kCAAkC,GAClD,8BAA8B,GAAG,SAAS,CAmB5C"}
package/dist/index.d.ts CHANGED
@@ -1542,6 +1542,7 @@ type CheckAllFirmwareReleaseParams = {
1542
1542
  firmwareType?: EFirmwareType;
1543
1543
  platform?: 'native' | 'desktop' | 'ext' | 'web' | 'web-embed';
1544
1544
  forceUpdateTargets?: FirmwareUpdatePlanForceTarget[];
1545
+ protocolV2ForceUpdateTargets?: FirmwareUpdateV4Target[];
1545
1546
  };
1546
1547
  declare function checkAllFirmwareRelease(connectId?: string, params?: CommonParams & CheckAllFirmwareReleaseParams): Response<AllFirmwareRelease>;
1547
1548
 
package/dist/index.js CHANGED
@@ -522,6 +522,10 @@ const PROTOCOL_V2_TARGETS = {
522
522
  SE03: 'se03',
523
523
  SE04: 'se04',
524
524
  };
525
+ const PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS = new Set([
526
+ ...Object.values(PROTOCOL_V2_TARGETS),
527
+ 'resource',
528
+ ]);
525
529
  const asRecord = (value) => value && typeof value === 'object' && !Array.isArray(value)
526
530
  ? value
527
531
  : undefined;
@@ -609,6 +613,18 @@ const validateFirmwareUpdatePlanForceTargets = (value) => {
609
613
  }
610
614
  return [...value];
611
615
  };
616
+ const validateProtocolV2FirmwareUpdateTargets = (value) => {
617
+ if (value === undefined) {
618
+ return [];
619
+ }
620
+ if (!Array.isArray(value) ||
621
+ value.length > PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.size ||
622
+ value.some(target => !PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.has(target)) ||
623
+ new Set(value).size !== value.length) {
624
+ return planError('Protocol V2 firmware update targets are invalid');
625
+ }
626
+ return [...value];
627
+ };
612
628
  const assertExactKeys = (value, required, optional = []) => {
613
629
  const allowed = new Set([...required, ...optional]);
614
630
  if (required.some(key => !Object.prototype.hasOwnProperty.call(value, key)) ||
@@ -773,7 +789,7 @@ const selectResourceUrl = ({ release, features, platform, }) => {
773
789
  };
774
790
  const getExecutor = (features) => {
775
791
  const deviceType = getDeviceType(features);
776
- if (deviceType === hdShared.EDeviceType.Pro2) {
792
+ if (deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo) {
777
793
  return 'v4';
778
794
  }
779
795
  if (deviceType === hdShared.EDeviceType.Pro &&
@@ -782,7 +798,7 @@ const getExecutor = (features) => {
782
798
  }
783
799
  return 'v2';
784
800
  };
785
- const buildProtocolV2Artifacts = (release, { includeComponents = true, includeResources = true, } = {}) => {
801
+ const buildProtocolV2Artifacts = (release, { includeComponents = true, includeResources = true, componentTargets: selectedComponentTargets, } = {}) => {
786
802
  var _a;
787
803
  const components = asRecord(release.components);
788
804
  if (includeComponents && !components) {
@@ -794,23 +810,32 @@ const buildProtocolV2Artifacts = (release, { includeComponents = true, includeRe
794
810
  const componentKeys = includeComponents && components
795
811
  ? [...installOrder, ...Object.keys(components).filter(key => !installOrder.includes(key))]
796
812
  : [];
813
+ const selectedComponentKeys = selectedComponentTargets
814
+ ? componentKeys.filter(key => {
815
+ var _a;
816
+ const component = asRecord(components === null || components === void 0 ? void 0 : components[key]);
817
+ const targetName = (_a = asString(component === null || component === void 0 ? void 0 : component.target)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
818
+ const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
819
+ return !!target && selectedComponentTargets.has(target);
820
+ })
821
+ : componentKeys;
797
822
  const artifacts = [];
798
823
  const targets = [];
799
- const componentTargets = new Set();
800
- for (const key of componentKeys) {
824
+ const componentTargetSet = new Set();
825
+ for (const key of selectedComponentKeys) {
801
826
  const component = asRecord(components === null || components === void 0 ? void 0 : components[key]);
802
827
  const targetName = (_a = asString(component === null || component === void 0 ? void 0 : component.target)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
828
+ const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
803
829
  if (targetName === 'ROMLOADER') {
804
830
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 ROMLOADER requires its dedicated loader flow', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
805
831
  }
806
- const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
807
832
  if (!component || !target) {
808
833
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 component ${key} has an unsupported target`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
809
834
  }
810
- if (componentTargets.has(target)) {
835
+ if (componentTargetSet.has(target)) {
811
836
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 component ${key} duplicates target ${target}`, { firmwareUpdateCode: 'FirmwarePlanInvalid' });
812
837
  }
813
- componentTargets.add(target);
838
+ componentTargetSet.add(target);
814
839
  artifacts.push(Object.assign(Object.assign({ artifactId: `component:${target}`, role: 'component', target, url: assertArtifactUrl(component.url, `Protocol V2 component ${key}`), container: 'raw', logicalName: key }, asIntegrity({
815
840
  size: component.expectedSize,
816
841
  sha256: component.fingerprint,
@@ -865,6 +890,63 @@ const assertForcedTargetsRepresented = ({ executor, forcedTargets, artifacts, ta
865
890
  }
866
891
  }
867
892
  };
893
+ const finalizeFirmwareUpdatePlan = ({ features, firmwareType, platform, artifacts, targetsToUpdate, }) => {
894
+ const executor = getExecutor(features);
895
+ const bootloaderMode = resolveDeviceBootloaderMode(features);
896
+ const reportedIdentity = getDeviceUUID(features);
897
+ const deviceIdentity = reportedIdentity === 'unavailable' ? '' : reportedIdentity;
898
+ if (artifacts.length > 0 &&
899
+ (platform === 'native' || platform === 'desktop') &&
900
+ !deviceIdentity &&
901
+ !(bootloaderMode && executor === 'v2')) {
902
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware update requires a stable device identity', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
903
+ }
904
+ const planWithoutDigest = {
905
+ schemaVersion: 2,
906
+ executor,
907
+ deviceIdentity: deviceIdentity || 'unavailable',
908
+ deviceModel: String(getDeviceType(features)),
909
+ firmwareType,
910
+ platform,
911
+ artifacts,
912
+ targetsToUpdate,
913
+ };
914
+ return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
915
+ };
916
+ const buildProtocolV2FirmwareUpdatePlan = ({ features, firmwareType, platform, release, targetsToUpdate, forceUpdateTargets, resourceArchiveAvailable, }) => {
917
+ const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
918
+ if (validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
919
+ planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
920
+ }
921
+ const requestedComponentTargets = new Set(targetsToUpdate.filter(target => target !== 'resource'));
922
+ if (getDeviceType(features) === hdShared.EDeviceType.Neo &&
923
+ (requestedComponentTargets.has('se03') || requestedComponentTargets.has('se04'))) {
924
+ planError('Neo does not support Protocol V2 targets se03 or se04');
925
+ }
926
+ const protocolV2 = buildProtocolV2Artifacts(release !== null && release !== void 0 ? release : {}, {
927
+ includeComponents: requestedComponentTargets.size > 0,
928
+ includeResources: false,
929
+ componentTargets: requestedComponentTargets,
930
+ });
931
+ const representedTargets = new Set(protocolV2.targets);
932
+ const missingTarget = Array.from(requestedComponentTargets).find(target => !representedTargets.has(target));
933
+ if (missingTarget) {
934
+ planError(`Protocol V2 release does not contain requested target ${missingTarget}`);
935
+ }
936
+ if (validatedForceTargets.includes('firmware') && protocolV2.targets.length === 0) {
937
+ planError('Forced firmware update target firmware is not represented by the plan');
938
+ }
939
+ if (validatedForceTargets.includes('resource') && !resourceArchiveAvailable) {
940
+ planError('Forced firmware update target resource has no Protocol V2 resource archive');
941
+ }
942
+ return finalizeFirmwareUpdatePlan({
943
+ features,
944
+ firmwareType,
945
+ platform,
946
+ artifacts: protocolV2.artifacts,
947
+ targetsToUpdate: protocolV2.targets,
948
+ });
949
+ };
868
950
  const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, ble, bootloader, forceUpdateTargets, }) => {
869
951
  var _a, _b, _c, _d, _e, _f, _g;
870
952
  const executor = getExecutor(features);
@@ -951,25 +1033,13 @@ const buildFirmwareUpdatePlan = ({ features, firmwareType, platform, firmware, b
951
1033
  artifacts,
952
1034
  targetsToUpdate,
953
1035
  });
954
- const reportedIdentity = getDeviceUUID(features);
955
- const deviceIdentity = reportedIdentity === 'unavailable' ? '' : reportedIdentity;
956
- if (artifacts.length > 0 &&
957
- (platform === 'native' || platform === 'desktop') &&
958
- !deviceIdentity &&
959
- !(bootloaderMode && executor === 'v2')) {
960
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Prepared firmware update requires a stable device identity', { firmwareUpdateCode: 'FirmwarePlanInvalid' });
961
- }
962
- const planWithoutDigest = {
963
- schemaVersion: 2,
964
- executor,
965
- deviceIdentity: deviceIdentity || 'unavailable',
966
- deviceModel: String(getDeviceType(features)),
1036
+ return finalizeFirmwareUpdatePlan({
1037
+ features,
967
1038
  firmwareType,
968
1039
  platform,
969
1040
  artifacts,
970
1041
  targetsToUpdate,
971
- };
972
- return assertFirmwareUpdatePlan(Object.assign(Object.assign({}, planWithoutDigest), { planDigest: digestFirmwareUpdatePlan(planWithoutDigest) }));
1042
+ });
973
1043
  };
974
1044
 
975
1045
  const preparedPlanError = (message) => {
@@ -41925,7 +41995,7 @@ const getFirmwareUpdateField = ({ features, updateType, targetVersion, firmwareT
41925
41995
  if (deviceType === hdShared.EDeviceType.Pro) {
41926
41996
  return latestFirmwareField;
41927
41997
  }
41928
- if (deviceType === hdShared.EDeviceType.Pro2) {
41998
+ if (deviceType === hdShared.EDeviceType.Pro2 || deviceType === hdShared.EDeviceType.Neo) {
41929
41999
  return 'firmware-v1';
41930
42000
  }
41931
42001
  return 'firmware';
@@ -41957,7 +42027,7 @@ const getFirmwareUpdateFieldArray = (features, updateType) => {
41957
42027
  if (deviceType === 'pro') {
41958
42028
  return ['firmware-v8'];
41959
42029
  }
41960
- if (deviceType === 'pro2') {
42030
+ if (deviceType === 'pro2' || deviceType === 'neo') {
41961
42031
  return ['firmware-v1'];
41962
42032
  }
41963
42033
  return ['firmware'];
@@ -47688,9 +47758,11 @@ class CheckAllFirmwareRelease extends BaseMethod {
47688
47758
  });
47689
47759
  }
47690
47760
  runProtocolV2() {
47761
+ var _a;
47691
47762
  return __awaiter(this, void 0, void 0, function* () {
47692
- const { checkFirmwareHash = false, firmwareType: firmwareTypeParam } = this
47693
- .payload;
47763
+ const { checkFirmwareHash = false, firmwareType: firmwareTypeParam, platform, forceUpdateTargets, protocolV2ForceUpdateTargets, } = this.payload;
47764
+ const validatedForceUpdateTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
47765
+ const validatedProtocolV2ForceUpdateTargets = validateProtocolV2FirmwareUpdateTargets(protocolV2ForceUpdateTargets);
47694
47766
  const { state, features, firmwareType, release } = yield loadProtocolV2FirmwareReleaseContext({
47695
47767
  device: this.device,
47696
47768
  firmwareType: firmwareTypeParam,
@@ -47709,10 +47781,57 @@ class CheckAllFirmwareRelease extends BaseMethod {
47709
47781
  const resourceSource = DataManager.getProtocolV2ResourceSource(resourceDeviceType);
47710
47782
  const resourceStatus = 'unknown';
47711
47783
  const resourcePreparationRequired = !!resourceSource;
47784
+ const detectedComponentTargets = validatedForceUpdateTargets.includes('firmware')
47785
+ ? plan.components.flatMap(component => component.updateTarget ? [component.updateTarget] : [])
47786
+ : plan.targetsToUpdate;
47787
+ const componentTargetsToUpdate = Array.from(new Set([
47788
+ ...detectedComponentTargets,
47789
+ ...validatedProtocolV2ForceUpdateTargets.filter(target => target !== 'resource'),
47790
+ ]));
47791
+ const forceResourceUpdate = validatedForceUpdateTargets.includes('resource') ||
47792
+ validatedProtocolV2ForceUpdateTargets.includes('resource');
47712
47793
  const targetsToUpdate = Array.from(new Set([
47713
- ...plan.targetsToUpdate,
47714
- ...(resourcePreparationRequired ? ['resource'] : []),
47794
+ ...componentTargetsToUpdate,
47795
+ ...(resourcePreparationRequired || forceResourceUpdate ? ['resource'] : []),
47715
47796
  ]));
47797
+ let firmwareUpdatePlan;
47798
+ try {
47799
+ const shouldBuildFirmwareUpdatePlan = componentTargetsToUpdate.length > 0 ||
47800
+ validatedForceUpdateTargets.some(target => target !== 'resource') ||
47801
+ validatedProtocolV2ForceUpdateTargets.some(target => target !== 'resource') ||
47802
+ (forceResourceUpdate && !resourcePreparationRequired);
47803
+ const requestedPlatform = platform !== null && platform !== void 0 ? platform : 'web';
47804
+ const requiresDeviceIdentity = requestedPlatform === 'native' || requestedPlatform === 'desktop';
47805
+ const canBindPreparedPlan = !requiresDeviceIdentity || !!getDeviceSerialNo(features);
47806
+ if (shouldBuildFirmwareUpdatePlan) {
47807
+ const validatedPlan = buildProtocolV2FirmwareUpdatePlan({
47808
+ features,
47809
+ firmwareType,
47810
+ platform: canBindPreparedPlan ? requestedPlatform : 'web',
47811
+ release,
47812
+ targetsToUpdate,
47813
+ forceUpdateTargets: validatedForceUpdateTargets,
47814
+ resourceArchiveAvailable: resourcePreparationRequired,
47815
+ });
47816
+ firmwareUpdatePlan = canBindPreparedPlan ? validatedPlan : undefined;
47817
+ if (!canBindPreparedPlan) {
47818
+ Log$c.warn('[CheckAllFirmwareRelease] Protocol V2 device identity is unavailable; using the release result without a prepared Plan');
47819
+ }
47820
+ }
47821
+ else {
47822
+ firmwareUpdatePlan = undefined;
47823
+ }
47824
+ }
47825
+ catch (error) {
47826
+ if (validatedForceUpdateTargets.length > 0 ||
47827
+ validatedProtocolV2ForceUpdateTargets.length > 0 ||
47828
+ !(error instanceof hdShared.HardwareError) ||
47829
+ ((_a = error.params) === null || _a === void 0 ? void 0 : _a.firmwareUpdateCode) !== 'FirmwarePlanInvalid') {
47830
+ throw error;
47831
+ }
47832
+ Log$c.warn('[CheckAllFirmwareRelease] Optional Protocol V2 firmware Plan is unavailable; using the release result');
47833
+ firmwareUpdatePlan = undefined;
47834
+ }
47716
47835
  const firmwarePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_MAIN_FIRMWARE_TARGETS);
47717
47836
  const blePlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BLE_TARGETS);
47718
47837
  const bootloaderPlan = summarizeProtocolV2FirmwareRelease(plan, PROTOCOL_V2_BOOTLOADER_TARGETS);
@@ -47728,7 +47847,8 @@ class CheckAllFirmwareRelease extends BaseMethod {
47728
47847
  state,
47729
47848
  release: getProtocolV2ComponentReleaseInfo(plan, 'BOOTLOADER'),
47730
47849
  }), features, protocol: 'V2', deviceType: state.identity.deviceType }, plan), { status,
47731
- resourceStatus, resourceArchive: resourceSource, resourcePreparationRequired, hasUpgrade: plan.hasUpgrade || resourcePreparationRequired, targetsToUpdate });
47850
+ resourceStatus, resourceArchive: resourceSource, resourcePreparationRequired, hasUpgrade: targetsToUpdate.length > 0, targetsToUpdate,
47851
+ firmwareUpdatePlan });
47732
47852
  });
47733
47853
  }
47734
47854
  }
@@ -62,6 +62,7 @@ export type CheckAllFirmwareReleaseParams = {
62
62
  firmwareType?: EFirmwareType;
63
63
  platform?: 'native' | 'desktop' | 'ext' | 'web' | 'web-embed';
64
64
  forceUpdateTargets?: FirmwareUpdatePlanForceTarget[];
65
+ protocolV2ForceUpdateTargets?: FirmwareUpdateV4Target[];
65
66
  };
66
67
  export declare function checkAllFirmwareRelease(connectId?: string, params?: CommonParams & CheckAllFirmwareReleaseParams): Response<AllFirmwareRelease>;
67
68
  //# sourceMappingURL=checkAllFirmwareRelease.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"checkAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../../src/types/api/checkAllFirmwareRelease.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"checkAllFirmwareRelease.d.ts","sourceRoot":"","sources":["../../../src/types/api/checkAllFirmwareRelease.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-core",
3
- "version": "1.2.0-alpha.82",
3
+ "version": "1.2.0-alpha.84",
4
4
  "description": "Core processes and APIs for communicating with OneKey hardware devices.",
5
5
  "author": "OneKey",
6
6
  "homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
@@ -25,8 +25,8 @@
25
25
  "url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
26
26
  },
27
27
  "dependencies": {
28
- "@onekeyfe/hd-shared": "1.2.0-alpha.82",
29
- "@onekeyfe/hd-transport": "1.2.0-alpha.82",
28
+ "@onekeyfe/hd-shared": "1.2.0-alpha.84",
29
+ "@onekeyfe/hd-transport": "1.2.0-alpha.84",
30
30
  "axios": "1.15.2",
31
31
  "bignumber.js": "^9.0.2",
32
32
  "bytebuffer": "^5.0.1",
@@ -44,5 +44,5 @@
44
44
  "@types/w3c-web-usb": "^1.0.10",
45
45
  "@types/web-bluetooth": "^0.0.21"
46
46
  },
47
- "gitHead": "7b2b6f5b2f046f5ff2e35e14735ba3918c258054"
47
+ "gitHead": "577746142ef64d2c97de487c7a9cc8a5a0422e0b"
48
48
  }
@@ -11,7 +11,9 @@ import {
11
11
  } from './firmware/releaseHelper';
12
12
  import {
13
13
  buildFirmwareUpdatePlan,
14
+ buildProtocolV2FirmwareUpdatePlan,
14
15
  validateFirmwareUpdatePlanForceTargets,
16
+ validateProtocolV2FirmwareUpdateTargets,
15
17
  } from './firmware/FirmwareUpdatePlan';
16
18
  import {
17
19
  PROTOCOL_V2_BLE_TARGETS,
@@ -26,6 +28,7 @@ import { getBridgeReleaseInfo } from '../utils/bridgeUpdate';
26
28
  import {
27
29
  LoggerNames,
28
30
  getDeviceFirmwareVersion,
31
+ getDeviceSerialNo,
29
32
  getDeviceType,
30
33
  getFirmwareType,
31
34
  getLogger,
@@ -384,8 +387,17 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
384
387
  }
385
388
 
386
389
  private async runProtocolV2(): Promise<AllFirmwareRelease> {
387
- const { checkFirmwareHash = false, firmwareType: firmwareTypeParam } = this
388
- .payload as CheckAllFirmwareReleaseParams;
390
+ const {
391
+ checkFirmwareHash = false,
392
+ firmwareType: firmwareTypeParam,
393
+ platform,
394
+ forceUpdateTargets,
395
+ protocolV2ForceUpdateTargets,
396
+ } = this.payload as CheckAllFirmwareReleaseParams;
397
+ const validatedForceUpdateTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
398
+ const validatedProtocolV2ForceUpdateTargets = validateProtocolV2FirmwareUpdateTargets(
399
+ protocolV2ForceUpdateTargets
400
+ );
389
401
  const { state, features, firmwareType, release } = await loadProtocolV2FirmwareReleaseContext({
390
402
  device: this.device,
391
403
  firmwareType: firmwareTypeParam,
@@ -405,12 +417,70 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
405
417
  const resourceSource = DataManager.getProtocolV2ResourceSource(resourceDeviceType);
406
418
  const resourceStatus = 'unknown' as const;
407
419
  const resourcePreparationRequired = !!resourceSource;
420
+ const detectedComponentTargets = validatedForceUpdateTargets.includes('firmware')
421
+ ? plan.components.flatMap(component =>
422
+ component.updateTarget ? [component.updateTarget] : []
423
+ )
424
+ : plan.targetsToUpdate;
425
+ const componentTargetsToUpdate = Array.from(
426
+ new Set([
427
+ ...detectedComponentTargets,
428
+ ...validatedProtocolV2ForceUpdateTargets.filter(target => target !== 'resource'),
429
+ ])
430
+ );
431
+ const forceResourceUpdate =
432
+ validatedForceUpdateTargets.includes('resource') ||
433
+ validatedProtocolV2ForceUpdateTargets.includes('resource');
408
434
  const targetsToUpdate = Array.from(
409
435
  new Set([
410
- ...plan.targetsToUpdate,
411
- ...(resourcePreparationRequired ? (['resource'] as const) : []),
436
+ ...componentTargetsToUpdate,
437
+ ...(resourcePreparationRequired || forceResourceUpdate ? (['resource'] as const) : []),
412
438
  ])
413
439
  );
440
+ let firmwareUpdatePlan: FirmwareUpdatePlan | undefined;
441
+ try {
442
+ const shouldBuildFirmwareUpdatePlan =
443
+ componentTargetsToUpdate.length > 0 ||
444
+ validatedForceUpdateTargets.some(target => target !== 'resource') ||
445
+ validatedProtocolV2ForceUpdateTargets.some(target => target !== 'resource') ||
446
+ (forceResourceUpdate && !resourcePreparationRequired);
447
+ const requestedPlatform = platform ?? 'web';
448
+ const requiresDeviceIdentity =
449
+ requestedPlatform === 'native' || requestedPlatform === 'desktop';
450
+ const canBindPreparedPlan = !requiresDeviceIdentity || !!getDeviceSerialNo(features);
451
+ if (shouldBuildFirmwareUpdatePlan) {
452
+ const validatedPlan = buildProtocolV2FirmwareUpdatePlan({
453
+ features,
454
+ firmwareType,
455
+ platform: canBindPreparedPlan ? requestedPlatform : 'web',
456
+ release,
457
+ targetsToUpdate,
458
+ forceUpdateTargets: validatedForceUpdateTargets,
459
+ resourceArchiveAvailable: resourcePreparationRequired,
460
+ });
461
+ firmwareUpdatePlan = canBindPreparedPlan ? validatedPlan : undefined;
462
+ if (!canBindPreparedPlan) {
463
+ Log.warn(
464
+ '[CheckAllFirmwareRelease] Protocol V2 device identity is unavailable; using the release result without a prepared Plan'
465
+ );
466
+ }
467
+ } else {
468
+ firmwareUpdatePlan = undefined;
469
+ }
470
+ } catch (error) {
471
+ if (
472
+ validatedForceUpdateTargets.length > 0 ||
473
+ validatedProtocolV2ForceUpdateTargets.length > 0 ||
474
+ !(error instanceof HardwareError) ||
475
+ error.params?.firmwareUpdateCode !== 'FirmwarePlanInvalid'
476
+ ) {
477
+ throw error;
478
+ }
479
+ Log.warn(
480
+ '[CheckAllFirmwareRelease] Optional Protocol V2 firmware Plan is unavailable; using the release result'
481
+ );
482
+ firmwareUpdatePlan = undefined;
483
+ }
414
484
  const firmwarePlan = summarizeProtocolV2FirmwareRelease(
415
485
  plan,
416
486
  PROTOCOL_V2_MAIN_FIRMWARE_TARGETS
@@ -442,8 +512,9 @@ export default class CheckAllFirmwareRelease extends BaseMethod {
442
512
  resourceStatus,
443
513
  resourceArchive: resourceSource,
444
514
  resourcePreparationRequired,
445
- hasUpgrade: plan.hasUpgrade || resourcePreparationRequired,
515
+ hasUpgrade: targetsToUpdate.length > 0,
446
516
  targetsToUpdate,
517
+ firmwareUpdatePlan,
447
518
  };
448
519
  }
449
520
  }
@@ -10,6 +10,7 @@ import {
10
10
  getDeviceFirmwareVersion,
11
11
  } from '../../utils/deviceVersionUtils';
12
12
 
13
+ import type { FirmwareUpdateV4Target } from '../../types/api/firmwareUpdate';
13
14
  import type {
14
15
  FirmwareUpdatePlan,
15
16
  FirmwareUpdatePlanArtifact,
@@ -62,6 +63,11 @@ const PROTOCOL_V2_TARGETS: Readonly<
62
63
  SE04: 'se04',
63
64
  };
64
65
 
66
+ const PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS = new Set<FirmwareUpdateV4Target>([
67
+ ...Object.values(PROTOCOL_V2_TARGETS),
68
+ 'resource',
69
+ ]);
70
+
65
71
  const asRecord = (value: unknown): Record<string, unknown> | undefined =>
66
72
  value && typeof value === 'object' && !Array.isArray(value)
67
73
  ? (value as Record<string, unknown>)
@@ -191,6 +197,23 @@ export const validateFirmwareUpdatePlanForceTargets = (
191
197
  return [...value] as FirmwareUpdatePlanForceTarget[];
192
198
  };
193
199
 
200
+ export const validateProtocolV2FirmwareUpdateTargets = (
201
+ value: unknown
202
+ ): FirmwareUpdateV4Target[] => {
203
+ if (value === undefined) {
204
+ return [];
205
+ }
206
+ if (
207
+ !Array.isArray(value) ||
208
+ value.length > PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.size ||
209
+ value.some(target => !PROTOCOL_V2_FIRMWARE_UPDATE_TARGETS.has(target)) ||
210
+ new Set(value).size !== value.length
211
+ ) {
212
+ return planError('Protocol V2 firmware update targets are invalid');
213
+ }
214
+ return [...value] as FirmwareUpdateV4Target[];
215
+ };
216
+
194
217
  const assertExactKeys = (
195
218
  value: Record<string, unknown>,
196
219
  required: readonly string[],
@@ -405,7 +428,7 @@ const selectResourceUrl = ({
405
428
 
406
429
  const getExecutor = (features: Features): FirmwareUpdatePlan['executor'] => {
407
430
  const deviceType = getDeviceType(features);
408
- if (deviceType === EDeviceType.Pro2) {
431
+ if (deviceType === EDeviceType.Pro2 || deviceType === EDeviceType.Neo) {
409
432
  return 'v4';
410
433
  }
411
434
  if (
@@ -422,9 +445,11 @@ const buildProtocolV2Artifacts = (
422
445
  {
423
446
  includeComponents = true,
424
447
  includeResources = true,
448
+ componentTargets: selectedComponentTargets,
425
449
  }: {
426
450
  includeComponents?: boolean;
427
451
  includeResources?: boolean;
452
+ componentTargets?: ReadonlySet<FirmwareUpdatePlanTarget>;
428
453
  } = {}
429
454
  ): {
430
455
  artifacts: FirmwareUpdatePlanArtifact[];
@@ -445,12 +470,21 @@ const buildProtocolV2Artifacts = (
445
470
  includeComponents && components
446
471
  ? [...installOrder, ...Object.keys(components).filter(key => !installOrder.includes(key))]
447
472
  : [];
473
+ const selectedComponentKeys = selectedComponentTargets
474
+ ? componentKeys.filter(key => {
475
+ const component = asRecord(components?.[key]);
476
+ const targetName = asString(component?.target)?.toUpperCase();
477
+ const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
478
+ return !!target && selectedComponentTargets.has(target);
479
+ })
480
+ : componentKeys;
448
481
  const artifacts: FirmwareUpdatePlanArtifact[] = [];
449
482
  const targets: FirmwareUpdatePlanTarget[] = [];
450
- const componentTargets = new Set<FirmwareUpdatePlanTarget>();
451
- for (const key of componentKeys) {
483
+ const componentTargetSet = new Set<FirmwareUpdatePlanTarget>();
484
+ for (const key of selectedComponentKeys) {
452
485
  const component = asRecord(components?.[key]);
453
486
  const targetName = asString(component?.target)?.toUpperCase();
487
+ const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
454
488
  if (targetName === 'ROMLOADER') {
455
489
  throw ERRORS.TypedError(
456
490
  HardwareErrorCode.RuntimeError,
@@ -458,7 +492,6 @@ const buildProtocolV2Artifacts = (
458
492
  { firmwareUpdateCode: 'FirmwarePlanInvalid' }
459
493
  );
460
494
  }
461
- const target = targetName ? PROTOCOL_V2_TARGETS[targetName] : undefined;
462
495
  if (!component || !target) {
463
496
  throw ERRORS.TypedError(
464
497
  HardwareErrorCode.RuntimeError,
@@ -466,14 +499,14 @@ const buildProtocolV2Artifacts = (
466
499
  { firmwareUpdateCode: 'FirmwarePlanInvalid' }
467
500
  );
468
501
  }
469
- if (componentTargets.has(target)) {
502
+ if (componentTargetSet.has(target)) {
470
503
  throw ERRORS.TypedError(
471
504
  HardwareErrorCode.RuntimeError,
472
505
  `Protocol V2 component ${key} duplicates target ${target}`,
473
506
  { firmwareUpdateCode: 'FirmwarePlanInvalid' }
474
507
  );
475
508
  }
476
- componentTargets.add(target);
509
+ componentTargetSet.add(target);
477
510
  artifacts.push({
478
511
  artifactId: `component:${target}`,
479
512
  role: 'component',
@@ -587,6 +620,119 @@ const assertForcedTargetsRepresented = ({
587
620
  }
588
621
  };
589
622
 
623
+ const finalizeFirmwareUpdatePlan = ({
624
+ features,
625
+ firmwareType,
626
+ platform,
627
+ artifacts,
628
+ targetsToUpdate,
629
+ }: {
630
+ features: Features;
631
+ firmwareType: EFirmwareType;
632
+ platform: FirmwareUpdatePlatform;
633
+ artifacts: FirmwareUpdatePlanArtifact[];
634
+ targetsToUpdate: FirmwareUpdatePlanTarget[];
635
+ }): FirmwareUpdatePlan => {
636
+ const executor = getExecutor(features);
637
+ const bootloaderMode = resolveDeviceBootloaderMode(features);
638
+ // 'unavailable' is the reserved degraded-identity sentinel; a device-reported
639
+ // serial must never be able to collide with it.
640
+ const reportedIdentity = getDeviceUUID(features);
641
+ const deviceIdentity = reportedIdentity === 'unavailable' ? '' : reportedIdentity;
642
+ // Bootloader-mode classic-family devices (executor v2, e.g. classic1s) cannot report
643
+ // a serial number, so their recovery plans fall back to the degraded 'unavailable'
644
+ // identity. Binding is then enforced against the live device at install time instead
645
+ // (assertFirmwareUpdatePreparedPlanDeviceIdentity), and plan integrity by the digest.
646
+ // Pro (v3), Pro2, and Neo (v4) report a serial even in loader mode and stay strict.
647
+ if (
648
+ artifacts.length > 0 &&
649
+ (platform === 'native' || platform === 'desktop') &&
650
+ !deviceIdentity &&
651
+ !(bootloaderMode && executor === 'v2')
652
+ ) {
653
+ throw ERRORS.TypedError(
654
+ HardwareErrorCode.RuntimeError,
655
+ 'Prepared firmware update requires a stable device identity',
656
+ { firmwareUpdateCode: 'FirmwarePlanInvalid' }
657
+ );
658
+ }
659
+ const planWithoutDigest: Omit<FirmwareUpdatePlan, 'planDigest'> = {
660
+ schemaVersion: 2,
661
+ executor,
662
+ deviceIdentity: deviceIdentity || 'unavailable',
663
+ deviceModel: String(getDeviceType(features)),
664
+ firmwareType,
665
+ platform,
666
+ artifacts,
667
+ targetsToUpdate,
668
+ };
669
+ return assertFirmwareUpdatePlan({
670
+ ...planWithoutDigest,
671
+ planDigest: digestFirmwareUpdatePlan(planWithoutDigest),
672
+ });
673
+ };
674
+
675
+ export const buildProtocolV2FirmwareUpdatePlan = ({
676
+ features,
677
+ firmwareType,
678
+ platform,
679
+ release,
680
+ targetsToUpdate,
681
+ forceUpdateTargets,
682
+ resourceArchiveAvailable,
683
+ }: {
684
+ features: Features;
685
+ firmwareType: EFirmwareType;
686
+ platform: FirmwareUpdatePlatform;
687
+ release: ReleaseRecord | undefined;
688
+ targetsToUpdate: readonly FirmwareUpdateV4Target[];
689
+ forceUpdateTargets?: FirmwareUpdatePlanForceTarget[];
690
+ resourceArchiveAvailable: boolean;
691
+ }): FirmwareUpdatePlan => {
692
+ const validatedForceTargets = validateFirmwareUpdatePlanForceTargets(forceUpdateTargets);
693
+ if (validatedForceTargets.some(target => target === 'ble' || target === 'bootloader')) {
694
+ planError('Protocol V2 does not support forced BLE or legacy bootloader targets');
695
+ }
696
+
697
+ const requestedComponentTargets = new Set<FirmwareUpdatePlanTarget>(
698
+ targetsToUpdate.filter(target => target !== 'resource')
699
+ );
700
+ if (
701
+ getDeviceType(features) === EDeviceType.Neo &&
702
+ (requestedComponentTargets.has('se03') || requestedComponentTargets.has('se04'))
703
+ ) {
704
+ planError('Neo does not support Protocol V2 targets se03 or se04');
705
+ }
706
+ const protocolV2 = buildProtocolV2Artifacts(release ?? {}, {
707
+ includeComponents: requestedComponentTargets.size > 0,
708
+ includeResources: false,
709
+ componentTargets: requestedComponentTargets,
710
+ });
711
+ const representedTargets = new Set(protocolV2.targets);
712
+ const missingTarget = Array.from(requestedComponentTargets).find(
713
+ target => !representedTargets.has(target)
714
+ );
715
+ if (missingTarget) {
716
+ planError(`Protocol V2 release does not contain requested target ${missingTarget}`);
717
+ }
718
+ if (validatedForceTargets.includes('firmware') && protocolV2.targets.length === 0) {
719
+ planError('Forced firmware update target firmware is not represented by the plan');
720
+ }
721
+ if (validatedForceTargets.includes('resource') && !resourceArchiveAvailable) {
722
+ planError('Forced firmware update target resource has no Protocol V2 resource archive');
723
+ }
724
+
725
+ // Protocol V2 resource archives are materialized by the host into explicit
726
+ // resourceFiles. The prepared artifact plan therefore binds firmware components only.
727
+ return finalizeFirmwareUpdatePlan({
728
+ features,
729
+ firmwareType,
730
+ platform,
731
+ artifacts: protocolV2.artifacts,
732
+ targetsToUpdate: protocolV2.targets,
733
+ });
734
+ };
735
+
590
736
  export const buildFirmwareUpdatePlan = ({
591
737
  features,
592
738
  firmwareType,
@@ -733,40 +879,11 @@ export const buildFirmwareUpdatePlan = ({
733
879
  artifacts,
734
880
  targetsToUpdate,
735
881
  });
736
-
737
- // 'unavailable' is the reserved degraded-identity sentinel; a device-reported
738
- // serial must never be able to collide with it.
739
- const reportedIdentity = getDeviceUUID(features);
740
- const deviceIdentity = reportedIdentity === 'unavailable' ? '' : reportedIdentity;
741
- // Bootloader-mode classic-family devices (executor v2, e.g. classic1s) cannot report
742
- // a serial number, so their recovery plans fall back to the degraded 'unavailable'
743
- // identity. Binding is then enforced against the live device at install time instead
744
- // (assertFirmwareUpdatePreparedPlanDeviceIdentity), and plan integrity by the digest.
745
- // Pro (v3) and Pro2 (v4) report a serial even in bootloader mode and stay strict.
746
- if (
747
- artifacts.length > 0 &&
748
- (platform === 'native' || platform === 'desktop') &&
749
- !deviceIdentity &&
750
- !(bootloaderMode && executor === 'v2')
751
- ) {
752
- throw ERRORS.TypedError(
753
- HardwareErrorCode.RuntimeError,
754
- 'Prepared firmware update requires a stable device identity',
755
- { firmwareUpdateCode: 'FirmwarePlanInvalid' }
756
- );
757
- }
758
- const planWithoutDigest: Omit<FirmwareUpdatePlan, 'planDigest'> = {
759
- schemaVersion: 2,
760
- executor,
761
- deviceIdentity: deviceIdentity || 'unavailable',
762
- deviceModel: String(getDeviceType(features)),
882
+ return finalizeFirmwareUpdatePlan({
883
+ features,
763
884
  firmwareType,
764
885
  platform,
765
886
  artifacts,
766
887
  targetsToUpdate,
767
- };
768
- return assertFirmwareUpdatePlan({
769
- ...planWithoutDigest,
770
- planDigest: digestFirmwareUpdatePlan(planWithoutDigest),
771
888
  });
772
889
  };
@@ -135,6 +135,8 @@ export function toProtocolV2FirmwareReleaseInfo({
135
135
  return {
136
136
  shouldUpdate: plan.hasUpgrade,
137
137
  status: plan.status === 'unavailable' ? 'unknown' : plan.status,
138
+ // Protocol V2 components share package-set release notes. The optional
139
+ // bootloaderChangelog field belongs to the legacy Protocol V1 release model.
138
140
  changelog: plan.release ? [plan.release.changelog] : [],
139
141
  release,
140
142
  bootloaderMode: state.status.mode === 'bootloader' || state.status.mode === 'romloader',
@@ -89,6 +89,7 @@ export type CheckAllFirmwareReleaseParams = {
89
89
  firmwareType?: EFirmwareType;
90
90
  platform?: 'native' | 'desktop' | 'ext' | 'web' | 'web-embed';
91
91
  forceUpdateTargets?: FirmwareUpdatePlanForceTarget[];
92
+ protocolV2ForceUpdateTargets?: FirmwareUpdateV4Target[];
92
93
  };
93
94
 
94
95
  export declare function checkAllFirmwareRelease(
@@ -328,7 +328,7 @@ export const getFirmwareUpdateField = ({
328
328
  if (deviceType === EDeviceType.Pro) {
329
329
  return latestFirmwareField;
330
330
  }
331
- if (deviceType === EDeviceType.Pro2) {
331
+ if (deviceType === EDeviceType.Pro2 || deviceType === EDeviceType.Neo) {
332
332
  return 'firmware-v1';
333
333
  }
334
334
  return 'firmware';
@@ -374,7 +374,7 @@ export const getFirmwareUpdateFieldArray = (
374
374
  return ['firmware-v8'];
375
375
  }
376
376
 
377
- if (deviceType === 'pro2') {
377
+ if (deviceType === 'pro2' || deviceType === 'neo') {
378
378
  return ['firmware-v1'];
379
379
  }
380
380