@onekeyfe/hd-core 1.2.0-alpha.87 → 1.2.0-alpha.88

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.
@@ -90,9 +90,12 @@ describe('prepareFirmwareUpdateV4MemoryHost', () => {
90
90
  expect(sdk.registerFirmwareUpdateHostBinding).toHaveBeenCalledWith(
91
91
  expect.objectContaining({ preparedPlanDigest: host.preparedPlan.preparedPlanDigest })
92
92
  );
93
- expect(host.componentArtifacts.boot?.size).toBe(componentBinary.byteLength);
93
+ const componentArtifact = host.preparedPlan.artifacts.find(
94
+ artifact => artifact.target === 'boot'
95
+ )?.artifact;
96
+ expect(componentArtifact?.size).toBe(componentBinary.byteLength);
94
97
  const opened = await artifactReader!.open({
95
- artifactRef: host.componentArtifacts.boot!.artifactRef,
98
+ artifactRef: componentArtifact!.artifactRef,
96
99
  });
97
100
  const chunk = await artifactReader!.read({
98
101
  readerId: opened.readerId,
@@ -1,4 +1,7 @@
1
1
  import { EFirmwareType, ERRORS, HardwareErrorCode } from '@onekeyfe/hd-shared';
2
+ import { sha256 } from '@noble/hashes/sha256';
3
+ import { bytesToHex } from '@noble/hashes/utils';
4
+ import JSZip from 'jszip';
2
5
  import {
3
6
  DeviceRebootType,
4
7
  DeviceSessionPinType,
@@ -6329,6 +6332,356 @@ describe('Protocol V2 firmware update targets', () => {
6329
6332
  }
6330
6333
  });
6331
6334
 
6335
+ test('executes a prepared component plan without duplicated component inputs', async () => {
6336
+ const componentBinary = new Uint8Array([1, 2, 3]).buffer;
6337
+ const componentArtifact = {
6338
+ artifactRef: 'prepared-bootloader',
6339
+ size: componentBinary.byteLength,
6340
+ sha256: 'a'.repeat(64),
6341
+ };
6342
+ const planWithoutDigest = {
6343
+ schemaVersion: 2 as const,
6344
+ executor: 'v4' as const,
6345
+ deviceIdentity: 'PRO2-SERIAL',
6346
+ deviceModel: 'pro2',
6347
+ firmwareType: EFirmwareType.Universal,
6348
+ platform: 'web' as const,
6349
+ targetsToUpdate: ['boot' as const],
6350
+ artifacts: [
6351
+ {
6352
+ artifactId: 'component:boot',
6353
+ role: 'component' as const,
6354
+ target: 'boot' as const,
6355
+ url: 'https://example.com/bootloader.bin',
6356
+ container: 'raw' as const,
6357
+ logicalName: 'bootloader',
6358
+ targetVersion: '1.2.3',
6359
+ },
6360
+ ],
6361
+ };
6362
+ const preparedPlan = prepareFirmwareUpdatePlan({
6363
+ plan: {
6364
+ ...planWithoutDigest,
6365
+ planDigest: digestFirmwareUpdateContract(planWithoutDigest),
6366
+ },
6367
+ leaseRef: 'prepared-component-test',
6368
+ artifacts: [{ artifactId: 'component:boot', artifact: componentArtifact }],
6369
+ });
6370
+ const artifactReader = {
6371
+ open: jest.fn(() =>
6372
+ Promise.resolve({
6373
+ readerId: 'prepared-component-reader',
6374
+ size: componentBinary.byteLength,
6375
+ })
6376
+ ),
6377
+ read: jest.fn(({ offset, length }: { offset: number; length: number }) => {
6378
+ const data = componentBinary.slice(offset, offset + length);
6379
+ return Promise.resolve({
6380
+ data,
6381
+ bytesRead: data.byteLength,
6382
+ eof: offset + length === componentBinary.byteLength,
6383
+ });
6384
+ }),
6385
+ close: jest.fn(() => Promise.resolve()),
6386
+ };
6387
+ const hostBindingGeneration = registerFirmwareUpdateHostBinding({
6388
+ preparedPlanDigest: preparedPlan.preparedPlanDigest,
6389
+ artifactReader,
6390
+ });
6391
+ const releaseSpy = jest
6392
+ .spyOn(DataManager, 'getFirmwareLatestRelease')
6393
+ .mockReturnValue(undefined);
6394
+
6395
+ try {
6396
+ const method = new FirmwareUpdateV4({
6397
+ id: 1,
6398
+ payload: {
6399
+ method: 'firmwareUpdateV4',
6400
+ platform: 'web',
6401
+ preparedPlan,
6402
+ hostBindingGeneration,
6403
+ },
6404
+ });
6405
+
6406
+ expect(() => method.init()).not.toThrow();
6407
+ expect((method as any).params.targetsToUpdate).toEqual(['boot']);
6408
+ expect((method as any).params.expectedTargetVersions).toEqual({ boot: '1.2.3' });
6409
+ expect((method as any).params.componentArtifacts).toBeUndefined();
6410
+ (method as any).postTipMessage = jest.fn();
6411
+ (method as any).prepareProtocolV2ResourceSources = jest.fn().mockResolvedValue([]);
6412
+ (method as any).executeProtocolV2SourceUpdate = jest
6413
+ .fn()
6414
+ .mockResolvedValue('prepared-result');
6415
+
6416
+ await expect(
6417
+ (method as any).runProtocolV2PreparedArtifacts({} as Features, EFirmwareType.Universal)
6418
+ ).resolves.toBe('prepared-result');
6419
+ expect(releaseSpy).not.toHaveBeenCalled();
6420
+ expect(artifactReader.open).toHaveBeenCalledWith({ artifactRef: 'prepared-bootloader' });
6421
+ expect((method as any).executeProtocolV2SourceUpdate).toHaveBeenCalledWith({
6422
+ installSources: [
6423
+ expect.objectContaining({
6424
+ fileName: 'bootloader.bin',
6425
+ kind: 'bootloader',
6426
+ }),
6427
+ ],
6428
+ resourceSources: [],
6429
+ });
6430
+ } finally {
6431
+ releaseSpy.mockRestore();
6432
+ unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
6433
+ }
6434
+ });
6435
+
6436
+ test('executes a resource-only prepared plan without a live firmware release', async () => {
6437
+ const planWithoutDigest = {
6438
+ schemaVersion: 2 as const,
6439
+ executor: 'v4' as const,
6440
+ deviceIdentity: 'PRO2-SERIAL',
6441
+ deviceModel: 'pro2',
6442
+ firmwareType: EFirmwareType.Universal,
6443
+ platform: 'web' as const,
6444
+ targetsToUpdate: ['resource' as const],
6445
+ artifacts: [
6446
+ {
6447
+ artifactId: 'resource:archive',
6448
+ role: 'resourceBundle' as const,
6449
+ target: 'resource' as const,
6450
+ url: 'https://example.com/resource.zip',
6451
+ container: 'zip' as const,
6452
+ logicalName: 'protocol-v2-resource-archive',
6453
+ },
6454
+ ],
6455
+ };
6456
+ const preparedPlan = prepareFirmwareUpdatePlan({
6457
+ plan: {
6458
+ ...planWithoutDigest,
6459
+ planDigest: digestFirmwareUpdateContract(planWithoutDigest),
6460
+ },
6461
+ leaseRef: 'prepared-resource-only-test',
6462
+ artifacts: [
6463
+ {
6464
+ artifactId: 'resource:archive',
6465
+ artifact: {
6466
+ artifactRef: 'prepared-resource-archive',
6467
+ size: 3,
6468
+ sha256: 'a'.repeat(64),
6469
+ },
6470
+ materializedEntries: [
6471
+ {
6472
+ entryName: 'manifest.json',
6473
+ artifact: {
6474
+ artifactRef: 'prepared-resource-manifest',
6475
+ size: 2,
6476
+ sha256: 'b'.repeat(64),
6477
+ },
6478
+ },
6479
+ ],
6480
+ },
6481
+ ],
6482
+ });
6483
+ const hostBindingGeneration = registerFirmwareUpdateHostBinding({
6484
+ preparedPlanDigest: preparedPlan.preparedPlanDigest,
6485
+ artifactReader: {
6486
+ open: jest.fn(),
6487
+ read: jest.fn(),
6488
+ close: jest.fn(),
6489
+ },
6490
+ });
6491
+ const releaseSpy = jest
6492
+ .spyOn(DataManager, 'getFirmwareLatestRelease')
6493
+ .mockReturnValue(undefined);
6494
+
6495
+ try {
6496
+ const method = new FirmwareUpdateV4({
6497
+ id: 1,
6498
+ payload: {
6499
+ method: 'firmwareUpdateV4',
6500
+ platform: 'web',
6501
+ preparedPlan,
6502
+ hostBindingGeneration,
6503
+ },
6504
+ });
6505
+
6506
+ expect(() => method.init()).not.toThrow();
6507
+ (method as any).postTipMessage = jest.fn();
6508
+ const resourceSources = [{ kind: 'resource' }];
6509
+ (method as any).prepareProtocolV2ResourceSources = jest
6510
+ .fn()
6511
+ .mockResolvedValue(resourceSources);
6512
+ (method as any).executeProtocolV2SourceUpdate = jest
6513
+ .fn()
6514
+ .mockResolvedValue('resource-result');
6515
+
6516
+ await expect(
6517
+ (method as any).runProtocolV2PreparedArtifacts({} as Features, EFirmwareType.Universal)
6518
+ ).resolves.toBe('resource-result');
6519
+ expect(releaseSpy).not.toHaveBeenCalled();
6520
+ expect((method as any).executeProtocolV2SourceUpdate).toHaveBeenCalledWith({
6521
+ installSources: [],
6522
+ resourceSources,
6523
+ });
6524
+ } finally {
6525
+ releaseSpy.mockRestore();
6526
+ unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
6527
+ }
6528
+ });
6529
+
6530
+ test('executes a local resource ZIP without creating or matching a remote Plan', async () => {
6531
+ const imagesBinary = new Uint8Array([1, 2, 3]).buffer;
6532
+ const bootResourceBinary = new Uint8Array([4, 5, 6]).buffer;
6533
+ const manifest = {
6534
+ schema: 1,
6535
+ artifact_name: 'pro2-resource',
6536
+ release_name: 'local-development',
6537
+ variant: 'resource',
6538
+ commit: 'local',
6539
+ short_sha: 'local',
6540
+ timestamp_utc: '2026-08-09T00:00:00Z',
6541
+ core_version: '1.0.0',
6542
+ key_set: 'development',
6543
+ device_root: 'vol0:',
6544
+ restore_mode: 'bootloader_update',
6545
+ trees: [{ path: 'bundles', device: 'pro2' }],
6546
+ files: [
6547
+ {
6548
+ archive_path: 'bundles/images/images.okpkg',
6549
+ original_name: 'images.okpkg',
6550
+ device_path: 'vol0:/bundles/images/images.okpkg',
6551
+ size: imagesBinary.byteLength,
6552
+ sha256: bytesToHex(sha256(new Uint8Array(imagesBinary))),
6553
+ signed: true,
6554
+ sig_algo: 'ed25519',
6555
+ payload_version: '1.0.0',
6556
+ },
6557
+ {
6558
+ archive_path: 'loaders/bootloader/boot_resource.okpkg',
6559
+ original_name: 'boot_resource.okpkg',
6560
+ device_path: 'vol0:/loaders/bootloader/boot_resource.okpkg',
6561
+ size: bootResourceBinary.byteLength,
6562
+ sha256: bytesToHex(sha256(new Uint8Array(bootResourceBinary))),
6563
+ signed: true,
6564
+ sig_algo: 'ed25519',
6565
+ payload_version: '1.0.0',
6566
+ },
6567
+ ],
6568
+ };
6569
+ const zip = new JSZip();
6570
+ zip.file('manifest.json', JSON.stringify(manifest));
6571
+ zip.file('bundles/images/images.okpkg', imagesBinary);
6572
+ zip.file('loaders/bootloader/boot_resource.okpkg', bootResourceBinary);
6573
+ const resourceArchiveBinary = await zip.generateAsync({ type: 'arraybuffer' });
6574
+ const method = new FirmwareUpdateV4({
6575
+ id: 1,
6576
+ payload: {
6577
+ method: 'firmwareUpdateV4',
6578
+ platform: 'web',
6579
+ targetsToUpdate: ['resource'],
6580
+ resourceArchiveBinary,
6581
+ },
6582
+ });
6583
+ method.init();
6584
+ (method as any).captureProtocolV2PhysicalIdentity = jest.fn().mockResolvedValue(undefined);
6585
+ (method as any).postTipMessage = jest.fn();
6586
+ (method as any).device = stubDevice({
6587
+ originalDescriptor: { protocolType: 'V2' },
6588
+ features: { deviceType: 'pro2', firmwareVersion: '1.0.0', capabilities: [] },
6589
+ getCurrentDeviceType: () => 'pro2',
6590
+ });
6591
+ (method as any).executeProtocolV2Update = jest.fn().mockResolvedValue('local-resource-result');
6592
+ const releaseSpy = jest.spyOn(DataManager, 'getFirmwareLatestRelease');
6593
+ const reloadSpy = jest.spyOn(DataManager, 'forceReloadData');
6594
+
6595
+ try {
6596
+ await expect(method.run()).resolves.toBe('local-resource-result');
6597
+ expect(releaseSpy).not.toHaveBeenCalled();
6598
+ expect(reloadSpy).not.toHaveBeenCalled();
6599
+ expect((method as any).executeProtocolV2Update).toHaveBeenCalledWith(
6600
+ expect.objectContaining({
6601
+ resourceBundles: [
6602
+ expect.objectContaining({
6603
+ name: 'images.okpkg',
6604
+ binary: imagesBinary,
6605
+ devicePath: 'vol0:/bundles/images/images.okpkg',
6606
+ }),
6607
+ expect.objectContaining({
6608
+ name: 'boot_resource.okpkg',
6609
+ binary: bootResourceBinary,
6610
+ devicePath: 'vol0:/loaders/bootloader/boot_resource.okpkg',
6611
+ }),
6612
+ ],
6613
+ })
6614
+ );
6615
+ } finally {
6616
+ releaseSpy.mockRestore();
6617
+ reloadSpy.mockRestore();
6618
+ }
6619
+ });
6620
+
6621
+ test('rejects a local resource ZIP whose file hash does not match its manifest', async () => {
6622
+ const resourceBinary = new Uint8Array([1, 2, 3]).buffer;
6623
+ const bootResourceBinary = new Uint8Array([4, 5, 6]).buffer;
6624
+ const zip = new JSZip();
6625
+ zip.file(
6626
+ 'manifest.json',
6627
+ JSON.stringify({
6628
+ schema: 1,
6629
+ artifact_name: 'pro2-resource',
6630
+ release_name: 'local-development',
6631
+ variant: 'resource',
6632
+ commit: 'local',
6633
+ short_sha: 'local',
6634
+ timestamp_utc: '2026-08-09T00:00:00Z',
6635
+ core_version: '1.0.0',
6636
+ key_set: 'development',
6637
+ device_root: 'vol0:',
6638
+ restore_mode: 'bootloader_update',
6639
+ trees: [{ path: 'bundles', device: 'pro2' }],
6640
+ files: [
6641
+ {
6642
+ archive_path: 'bundles/images/images.okpkg',
6643
+ original_name: 'images.okpkg',
6644
+ device_path: 'vol0:/bundles/images/images.okpkg',
6645
+ size: resourceBinary.byteLength,
6646
+ sha256: '0'.repeat(64),
6647
+ signed: true,
6648
+ sig_algo: 'ed25519',
6649
+ payload_version: '1.0.0',
6650
+ },
6651
+ {
6652
+ archive_path: 'loaders/bootloader/boot_resource.okpkg',
6653
+ original_name: 'boot_resource.okpkg',
6654
+ device_path: 'vol0:/loaders/bootloader/boot_resource.okpkg',
6655
+ size: bootResourceBinary.byteLength,
6656
+ sha256: bytesToHex(sha256(new Uint8Array(bootResourceBinary))),
6657
+ signed: true,
6658
+ sig_algo: 'ed25519',
6659
+ payload_version: '1.0.0',
6660
+ },
6661
+ ],
6662
+ })
6663
+ );
6664
+ zip.file('bundles/images/images.okpkg', resourceBinary);
6665
+ zip.file('loaders/bootloader/boot_resource.okpkg', bootResourceBinary);
6666
+ const method = new FirmwareUpdateV4({
6667
+ id: 1,
6668
+ payload: {
6669
+ method: 'firmwareUpdateV4',
6670
+ platform: 'web',
6671
+ targetsToUpdate: ['resource'],
6672
+ },
6673
+ });
6674
+ method.init();
6675
+
6676
+ await expect(
6677
+ (method as any).prepareProtocolV2LocalResourceArchive(
6678
+ await zip.generateAsync({ type: 'arraybuffer' })
6679
+ )
6680
+ ).rejects.toThrow(
6681
+ 'Protocol V2 local resource file does not match manifest: bundles/images/images.okpkg'
6682
+ );
6683
+ });
6684
+
6332
6685
  test('keeps the legacy componentArtifacts and artifactReader path without a prepared Plan', async () => {
6333
6686
  const artifactReader = {
6334
6687
  open: jest.fn(),
@@ -25,6 +25,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
25
25
  private openProtocolV2MemorySource;
26
26
  private closeProtocolV2PreparedSources;
27
27
  private prepareProtocolV2InstallSources;
28
+ private prepareProtocolV2LocalResourceArchive;
28
29
  private prepareProtocolV2ResourceSources;
29
30
  private prepareProtocolV2ResourceArchiveSources;
30
31
  private runProtocolV2PreparedArtifacts;
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkD,MAAM,qBAAqB,CAAC;AAwBlG,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AA2B/E,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,6BAA6B,CAAC;AAgDrC,wBAAgB,wCAAwC,CACtD,UAAU,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,EAC5C,MAAM,EAAE,sBAAsB,QAgB/B;AAoUD,eAAO,MAAM,oCAAoC,WACvC,WAAW,GAAG,UAAU,eACnB,MAAM,GAAG,SAAS,YAKhC,CAAC;AAEF,eAAO,MAAM,iCAAiC,0BACrB,MAAM,uBACR,MAAM,iBACZ,MAAM,eACR,MAAM,SAsBpB,CAAC;AAUF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,OAAO,CAAC,sBAAsB,CAAC,CAAS;IAExC,qBAAqB;IAIrB,OAAO,CAAC,yBAAyB,CAA4B;IAE7D,OAAO,CAAC,2BAA2B,CAAS;IAE5C,OAAO,CAAC,iCAAiC,CAA6B;IAEtE,OAAO,CAAC,6BAA6B,CAAC,CAAW;IAEjD,OAAO,CAAC,6BAA6B,CAAS;IAE9C,IAAI;IAyGJ,OAAO,CAAC,8BAA8B;IAwBhC,GAAG;;;;;YAKK,aAAa;YAsGb,4BAA4B;YAkB5B,0BAA0B;YAY1B,8BAA8B;YAK9B,+BAA+B;YAqD/B,gCAAgC;YAgBhC,uCAAuC;YAwHvC,8BAA8B;IAsB5C,OAAO,CAAC,8BAA8B;IA0BtC,OAAO,CAAC,kCAAkC;IAc1C,OAAO,CAAC,gCAAgC;IAsDxC,OAAO,CAAC,6BAA6B;YAsBvB,2BAA2B;IAWzC,OAAO,CAAC,yBAAyB;IAKjC,OAAO,CAAC,kCAAkC;IAS1C,OAAO,CAAC,8BAA8B;YAMxB,iCAAiC;YAOjC,iCAAiC;YAkBjC,iCAAiC;IAM/C,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,mCAAmC;IAY3C,OAAO,CAAC,2BAA2B;IAsBnC,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,wBAAwB;YAkBlB,iCAAiC;YAmCjC,+BAA+B;IA6E7C,OAAO,CAAC,6BAA6B;YAMvB,8BAA8B;YA+C9B,kCAAkC;IA+BhD,OAAO,CAAC,0BAA0B;IAUlC,OAAO,CAAC,yBAAyB;IAc3B,6BAA6B;YAgCrB,+BAA+B;IAkD7C,OAAO,CAAC,6BAA6B;IAkCrC,OAAO,CAAC,8BAA8B;YA8CxB,uBAAuB;YAiCvB,6BAA6B;YAa7B,uBAAuB;YAiCvB,8BAA8B;YA8D9B,6BAA6B;IAuE3C,OAAO,CAAC,mCAAmC;YAI7B,0BAA0B;IAaxC,OAAO,CAAC,4BAA4B;IAyGpC,OAAO,CAAC,6BAA6B;YAcvB,uCAAuC;YA0JvC,gCAAgC;YAehC,yBAAyB;YAQzB,8BAA8B;IAQ5C,OAAO,CAAC,0BAA0B;YAkBpB,mCAAmC;YAWnC,qCAAqC;YAgDrC,yBAAyB;YA8DzB,8BAA8B;IAU5C,OAAO,CAAC,kCAAkC;YAQ5B,cAAc;YAuCd,6BAA6B;YAW7B,0BAA0B;YAS1B,6BAA6B;YAmB7B,gBAAgB;IAiB9B,OAAO,CAAC,qBAAqB;CAM9B"}
1
+ {"version":3,"file":"FirmwareUpdateV4.d.ts","sourceRoot":"","sources":["../../src/api/FirmwareUpdateV4.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAkD,MAAM,qBAAqB,CAAC;AAyBlG,OAAO,EAAE,wBAAwB,EAAE,MAAM,qCAAqC,CAAC;AA2B/E,OAAO,KAAK,EAEV,sBAAsB,EAEvB,MAAM,6BAA6B,CAAC;AAgDrC,wBAAgB,wCAAwC,CACtD,UAAU,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,EAC5C,MAAM,EAAE,sBAAsB,QAgB/B;AAqVD,eAAO,MAAM,oCAAoC,WACvC,WAAW,GAAG,UAAU,eACnB,MAAM,GAAG,SAAS,YAKhC,CAAC;AAEF,eAAO,MAAM,iCAAiC,0BACrB,MAAM,uBACR,MAAM,iBACZ,MAAM,eACR,MAAM,SAsBpB,CAAC;AAUF,MAAM,CAAC,OAAO,OAAO,gBAAiB,SAAQ,wBAAwB,CAAC,sBAAsB,CAAC;IAC5F,OAAO,CAAC,8BAA8B,CAAC,CAAS;IAEhD,OAAO,CAAC,sBAAsB,CAAC,CAAS;IAExC,qBAAqB;IAIrB,OAAO,CAAC,yBAAyB,CAA4B;IAE7D,OAAO,CAAC,2BAA2B,CAAS;IAE5C,OAAO,CAAC,iCAAiC,CAA6B;IAEtE,OAAO,CAAC,6BAA6B,CAAC,CAAW;IAEjD,OAAO,CAAC,6BAA6B,CAAS;IAE9C,IAAI;IAyJJ,OAAO,CAAC,8BAA8B;IAwBhC,GAAG;;;;;YAKK,aAAa;YAkHb,4BAA4B;YAkB5B,0BAA0B;YAY1B,8BAA8B;YAK9B,+BAA+B;YAqG/B,qCAAqC;YA8GrC,gCAAgC;YAgBhC,uCAAuC;YAwHvC,8BAA8B;IAsB5C,OAAO,CAAC,8BAA8B;IA0BtC,OAAO,CAAC,kCAAkC;IAc1C,OAAO,CAAC,gCAAgC;IAsDxC,OAAO,CAAC,6BAA6B;YAsBvB,2BAA2B;IAWzC,OAAO,CAAC,yBAAyB;IAKjC,OAAO,CAAC,kCAAkC;IAS1C,OAAO,CAAC,8BAA8B;YAMxB,iCAAiC;YAOjC,iCAAiC;YAkBjC,iCAAiC;IAM/C,OAAO,CAAC,uBAAuB;IAI/B,OAAO,CAAC,mCAAmC;IAY3C,OAAO,CAAC,2BAA2B;IAsBnC,OAAO,CAAC,yBAAyB;IAiBjC,OAAO,CAAC,wBAAwB;YAkBlB,iCAAiC;YAmCjC,+BAA+B;IA6E7C,OAAO,CAAC,6BAA6B;YAMvB,8BAA8B;YA+C9B,kCAAkC;IA+BhD,OAAO,CAAC,0BAA0B;IAUlC,OAAO,CAAC,yBAAyB;IAc3B,6BAA6B;YAgCrB,+BAA+B;IAkD7C,OAAO,CAAC,6BAA6B;IAkCrC,OAAO,CAAC,8BAA8B;YA8CxB,uBAAuB;YAiCvB,6BAA6B;YAa7B,uBAAuB;YA6CvB,8BAA8B;YA8D9B,6BAA6B;IAuE3C,OAAO,CAAC,mCAAmC;YAI7B,0BAA0B;IAaxC,OAAO,CAAC,4BAA4B;IAyGpC,OAAO,CAAC,6BAA6B;YAcvB,uCAAuC;YA0JvC,gCAAgC;YAehC,yBAAyB;YAQzB,8BAA8B;IAQ5C,OAAO,CAAC,0BAA0B;YAkBpB,mCAAmC;YAWnC,qCAAqC;YAgDrC,yBAAyB;YA8DzB,8BAA8B;IAU5C,OAAO,CAAC,kCAAkC;YAQ5B,cAAc;YAuCd,6BAA6B;YAW7B,0BAA0B;YAS1B,6BAA6B;YAmB7B,gBAAgB;IAiB9B,OAAO,CAAC,qBAAqB;CAM9B"}
@@ -1,5 +1,4 @@
1
1
  import type { CoreApi } from '../../types/api';
2
- import type { FirmwareArtifactReference, FirmwareUpdateV4Target } from '../../types/api/firmwareUpdate';
3
2
  import type { FirmwareUpdatePlan } from '../../types/api/firmwareUpdatePlan';
4
3
  export type FirmwareMemoryArtifactEntry = {
5
4
  entryName: string;
@@ -13,10 +12,6 @@ export type FirmwareMemoryArtifact = {
13
12
  export type FirmwareUpdateV4MemoryHost = {
14
13
  preparedPlan: ReturnType<CoreApi['prepareFirmwareUpdatePlan']>;
15
14
  hostBindingGeneration: number;
16
- targetsToUpdate: FirmwareUpdateV4Target[];
17
- expectedDeviceId: string;
18
- expectedTargetVersions: Partial<Record<FirmwareUpdateV4Target, string>>;
19
- componentArtifacts: Partial<Record<Exclude<FirmwareUpdateV4Target, 'resource'>, FirmwareArtifactReference>>;
20
15
  release: () => void;
21
16
  };
22
17
  export declare function prepareFirmwareUpdateV4MemoryHost({ sdk, plan, artifacts, }: {
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwareMemoryHost.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwareMemoryHost.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,KAAK,EAEV,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAE7E,MAAM,MAAM,2BAA2B,GAAG;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;IACpB,mBAAmB,CAAC,EAAE,2BAA2B,EAAE,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,YAAY,EAAE,UAAU,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,CAAC;IAC/D,qBAAqB,EAAE,MAAM,CAAC;IAC9B,eAAe,EAAE,sBAAsB,EAAE,CAAC;IAC1C,gBAAgB,EAAE,MAAM,CAAC;IACzB,sBAAsB,EAAE,OAAO,CAAC,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC,CAAC;IACxE,kBAAkB,EAAE,OAAO,CACzB,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,UAAU,CAAC,EAAE,yBAAyB,CAAC,CAC/E,CAAC;IACF,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AA6BF,wBAAgB,iCAAiC,CAAC,EAChD,GAAG,EACH,IAAI,EACJ,SAAS,GACV,EAAE;IACD,GAAG,EAAE,IAAI,CACP,OAAO,EACL,2BAA2B,GAC3B,mCAAmC,GACnC,qCAAqC,CACxC,CAAC;IACF,IAAI,EAAE,kBAAkB,CAAC;IACzB,SAAS,EAAE,sBAAsB,EAAE,CAAC;CACrC,GAAG,0BAA0B,CAkG7B"}
1
+ {"version":3,"file":"FirmwareMemoryHost.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwareMemoryHost.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAK/C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAE7E,MAAM,MAAM,2BAA2B,GAAG;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,CAAC;IACpB,mBAAmB,CAAC,EAAE,2BAA2B,EAAE,CAAC;CACrD,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACvC,YAAY,EAAE,UAAU,CAAC,OAAO,CAAC,2BAA2B,CAAC,CAAC,CAAC;IAC/D,qBAAqB,EAAE,MAAM,CAAC;IAC9B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAaF,wBAAgB,iCAAiC,CAAC,EAChD,GAAG,EACH,IAAI,EACJ,SAAS,GACV,EAAE;IACD,GAAG,EAAE,IAAI,CACP,OAAO,EACL,2BAA2B,GAC3B,mCAAmC,GACnC,qCAAqC,CACxC,CAAC;IACF,IAAI,EAAE,kBAAkB,CAAC;IACzB,SAAS,EAAE,sBAAsB,EAAE,CAAC;CACrC,GAAG,0BAA0B,CAoF7B"}
package/dist/index.d.ts CHANGED
@@ -1433,6 +1433,8 @@ interface FirmwareUpdateV4Params {
1433
1433
  se02Binary?: ArrayBuffer;
1434
1434
  se03Binary?: ArrayBuffer;
1435
1435
  se04Binary?: ArrayBuffer;
1436
+ /** Complete Protocol V2 resource ZIP for local development; never bound to a remote Plan. */
1437
+ resourceArchiveBinary?: ArrayBuffer;
1436
1438
  forcedUpdateRes?: boolean;
1437
1439
  artifactReader?: FirmwareArtifactReader;
1438
1440
  componentArtifacts?: Partial<Record<Exclude<FirmwareUpdateV4Target, 'resource'>, FirmwareArtifactReference>>;
@@ -4883,10 +4885,6 @@ type FirmwareMemoryArtifact = {
4883
4885
  type FirmwareUpdateV4MemoryHost = {
4884
4886
  preparedPlan: ReturnType<CoreApi['prepareFirmwareUpdatePlan']>;
4885
4887
  hostBindingGeneration: number;
4886
- targetsToUpdate: FirmwareUpdateV4Target[];
4887
- expectedDeviceId: string;
4888
- expectedTargetVersions: Partial<Record<FirmwareUpdateV4Target, string>>;
4889
- componentArtifacts: Partial<Record<Exclude<FirmwareUpdateV4Target, 'resource'>, FirmwareArtifactReference>>;
4890
4888
  release: () => void;
4891
4889
  };
4892
4890
  declare function prepareFirmwareUpdateV4MemoryHost({ sdk, plan, artifacts, }: {
package/dist/index.js CHANGED
@@ -51347,6 +51347,10 @@ const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map([
51347
51347
  [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE03, 'se03'],
51348
51348
  [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04, 'se04'],
51349
51349
  ]);
51350
+ const PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET = new Map(Object.values(PROTOCOL_V2_REMOTE_COMPONENT_TARGETS).map(target => [
51351
+ PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(target.targetId),
51352
+ target,
51353
+ ]));
51350
51354
  const PROTOCOL_V2_ROMLOADER_UNSUPPORTED_MESSAGE = 'FW_MGMT_TARGET_ROMLOADER is not accepted by the current Pro2 bootloader update request. Flash romloader with the loader-specific flow instead of firmwareUpdateV4.';
51351
51355
  const PROTOCOL_V2_TARGET_ID_BY_DECODED_NAME = new Map(Object.entries(ProtocolV2FirmwareTargetType).map(([key, value]) => [key, value]));
51352
51356
  const PROTOCOL_V2_TARGET_STATUS_BY_DECODED_NAME = new Map([
@@ -51542,6 +51546,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51542
51546
  { name: 'se02Binary', type: 'buffer' },
51543
51547
  { name: 'se03Binary', type: 'buffer' },
51544
51548
  { name: 'se04Binary', type: 'buffer' },
51549
+ { name: 'resourceArchiveBinary', type: 'buffer' },
51545
51550
  { name: 'firmwareType', type: 'string' },
51546
51551
  { name: 'targetsToUpdate', type: 'array', allowEmpty: true },
51547
51552
  { name: 'platform', type: 'string' },
@@ -51554,28 +51559,59 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51554
51559
  const preparedPlan = payload.preparedPlan
51555
51560
  ? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
51556
51561
  : undefined;
51562
+ const hasLocalArtifacts = [
51563
+ payload.bootloaderBinary,
51564
+ payload.romloaderBinary,
51565
+ payload.applicationP1Binary,
51566
+ payload.applicationP2Binary,
51567
+ payload.coprocessorBinary,
51568
+ payload.se01Binary,
51569
+ payload.se02Binary,
51570
+ payload.se03Binary,
51571
+ payload.se04Binary,
51572
+ payload.resourceArchiveBinary,
51573
+ ].some(Boolean);
51574
+ if (preparedPlan && hasLocalArtifacts) {
51575
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.CallMethodInvalidParameter, 'Prepared firmware plans cannot be combined with local firmware or resource binaries');
51576
+ }
51557
51577
  const hostBinding = payload.hostBindingGeneration !== undefined
51558
51578
  ? resolveFirmwareUpdateHostBinding(payload.hostBindingGeneration, preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.preparedPlanDigest)
51559
51579
  : undefined;
51560
51580
  if (preparedPlan) {
51561
- const componentArtifacts = ((_a = payload.componentArtifacts) !== null && _a !== void 0 ? _a : {});
51562
51581
  assertFirmwareUpdatePreparedPlanBinding({
51563
51582
  preparedPlan,
51564
51583
  executor: 'v4',
51565
51584
  platform: payload.platform,
51566
- scopeTargets: ['boot', 'app_v1', 'app_v2', 'coprocessor', 'se01', 'se02', 'se03', 'se04'],
51567
- bindings: [
51568
- ...Object.entries(componentArtifacts).flatMap(([target, artifact]) => artifact
51569
- ? [
51570
- {
51571
- target: target,
51572
- artifact,
51573
- },
51574
- ]
51575
- : []),
51576
- ],
51585
+ scopeTargets: [],
51586
+ bindings: [],
51577
51587
  });
51588
+ if (payload.componentArtifacts) {
51589
+ const componentBindings = Object.entries(payload.componentArtifacts).flatMap(([target, artifact]) => artifact
51590
+ ? [
51591
+ {
51592
+ target: target,
51593
+ artifact: artifact,
51594
+ },
51595
+ ]
51596
+ : []);
51597
+ assertFirmwareUpdatePreparedPlanBinding({
51598
+ preparedPlan,
51599
+ executor: 'v4',
51600
+ platform: payload.platform,
51601
+ scopeTargets: componentBindings.map(binding => binding.target),
51602
+ bindings: componentBindings,
51603
+ });
51604
+ }
51578
51605
  }
51606
+ const preparedExpectedTargetVersions = preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.artifacts.reduce((result, artifact) => {
51607
+ if (artifact.role === 'component' &&
51608
+ artifact.target !== 'resource' &&
51609
+ artifact.targetVersion &&
51610
+ PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET.has(artifact.target)) {
51611
+ result[artifact.target] = artifact.targetVersion;
51612
+ }
51613
+ return result;
51614
+ }, {});
51579
51615
  this.params = {
51580
51616
  preparedPlan,
51581
51617
  chunkSize: payload.chunkSize,
@@ -51589,13 +51625,18 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51589
51625
  se02Binary: payload.se02Binary,
51590
51626
  se03Binary: payload.se03Binary,
51591
51627
  se04Binary: payload.se04Binary,
51592
- firmwareType: payload.firmwareType,
51593
- targetsToUpdate: payload.targetsToUpdate,
51594
- expectedTargetVersions: payload.expectedTargetVersions,
51628
+ resourceArchiveBinary: payload.resourceArchiveBinary,
51629
+ firmwareType: (_a = preparedPlan === null || preparedPlan === void 0 ? void 0 : preparedPlan.firmwareType) !== null && _a !== void 0 ? _a : payload.firmwareType,
51630
+ targetsToUpdate: preparedPlan
51631
+ ? [...preparedPlan.targetsToUpdate]
51632
+ : payload.targetsToUpdate,
51633
+ expectedTargetVersions: preparedPlan
51634
+ ? preparedExpectedTargetVersions
51635
+ : payload.expectedTargetVersions,
51595
51636
  platform: payload.platform,
51596
51637
  expectedDeviceId: payload.expectedDeviceId,
51597
51638
  artifactReader: (_b = hostBinding === null || hostBinding === void 0 ? void 0 : hostBinding.artifactReader) !== null && _b !== void 0 ? _b : payload.artifactReader,
51598
- componentArtifacts: payload.componentArtifacts,
51639
+ componentArtifacts: preparedPlan ? undefined : payload.componentArtifacts,
51599
51640
  };
51600
51641
  }
51601
51642
  getProtocolV2FirmwareChunkSize(direction, filePath) {
@@ -51646,6 +51687,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51646
51687
  let fwBinaryMap = [];
51647
51688
  let bootloaderBinary = null;
51648
51689
  let installItems;
51690
+ let resourceBundles = [];
51649
51691
  try {
51650
51692
  this.postTipMessage(exports.FirmwareUpdateTipMessage.StartDownloadFirmware);
51651
51693
  fwBinaryMap = this.collectExplicitTargetBinaries();
@@ -51659,9 +51701,12 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51659
51701
  ? missingFirmwareTargets.length > 0
51660
51702
  : explicitInstallItems.length === 0;
51661
51703
  if (wantsResources) {
51662
- throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource manifest must be prepared by the external firmware host', {
51663
- firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
51664
- });
51704
+ if (!this.params.resourceArchiveBinary) {
51705
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 resource archive must be provided for a local resource update', {
51706
+ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
51707
+ });
51708
+ }
51709
+ resourceBundles = yield this.prepareProtocolV2LocalResourceArchive(this.params.resourceArchiveBinary);
51665
51710
  }
51666
51711
  if (needsRemoteFirmware &&
51667
51712
  (this.params.artifactReader ||
@@ -51693,11 +51738,14 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51693
51738
  }
51694
51739
  throw normalizeFirmwarePreparationError(err);
51695
51740
  }
51696
- if (!bootloaderBinary && fwBinaryMap.length === 0 && !(installItems === null || installItems === void 0 ? void 0 : installItems.length)) {
51741
+ if (!bootloaderBinary &&
51742
+ fwBinaryMap.length === 0 &&
51743
+ !(installItems === null || installItems === void 0 ? void 0 : installItems.length) &&
51744
+ resourceBundles.length === 0) {
51697
51745
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.FirmwareUpdateDownloadFailed, 'No firmware to update');
51698
51746
  }
51699
- return this.executeProtocolV2Update(Object.assign({ fwBinaryMap,
51700
- bootloaderBinary }, (installItems ? { installItems } : undefined)));
51747
+ return this.executeProtocolV2Update(Object.assign(Object.assign({ fwBinaryMap,
51748
+ bootloaderBinary }, (installItems ? { installItems } : undefined)), (resourceBundles.length > 0 ? { resourceBundles } : undefined)));
51701
51749
  });
51702
51750
  }
51703
51751
  openProtocolV2PreparedSource(artifact) {
@@ -51734,6 +51782,34 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51734
51782
  prepareProtocolV2InstallSources(firmwareType, features) {
51735
51783
  var _a, _b;
51736
51784
  return __awaiter(this, void 0, void 0, function* () {
51785
+ if (this.params.preparedPlan) {
51786
+ const requestedTargets = new Set(this.params.preparedPlan.targetsToUpdate.filter((target) => target !== 'resource'));
51787
+ const installSources = [];
51788
+ const preparedTargets = new Set();
51789
+ for (const artifact of this.params.preparedPlan.artifacts) {
51790
+ if (artifact.target !== 'resource') {
51791
+ const target = artifact.target;
51792
+ const installTarget = PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET.get(target);
51793
+ if (!requestedTargets.has(target) ||
51794
+ artifact.role !== 'component' ||
51795
+ artifact.container !== 'raw' ||
51796
+ !installTarget ||
51797
+ preparedTargets.has(target)) {
51798
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 prepared component artifact is invalid: ${artifact.artifactId}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51799
+ }
51800
+ installSources.push(Object.assign(Object.assign({}, installTarget), { source: yield this.openProtocolV2PreparedSource(artifact.artifact) }));
51801
+ preparedTargets.add(target);
51802
+ }
51803
+ }
51804
+ const missingTarget = Array.from(requestedTargets).find(target => !preparedTargets.has(target));
51805
+ if (missingTarget) {
51806
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 ${missingTarget} artifact is not prepared`, {
51807
+ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
51808
+ artifactName: missingTarget,
51809
+ });
51810
+ }
51811
+ return installSources;
51812
+ }
51737
51813
  const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
51738
51814
  if (!release) {
51739
51815
  throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 firmware release is unavailable');
@@ -51764,6 +51840,73 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
51764
51840
  return installSources;
51765
51841
  });
51766
51842
  }
51843
+ prepareProtocolV2LocalResourceArchive(binary) {
51844
+ var _a;
51845
+ return __awaiter(this, void 0, void 0, function* () {
51846
+ const zip = yield JSZip__default["default"].loadAsync(binary);
51847
+ const entries = Object.values(zip.files).filter(entry => !entry.dir);
51848
+ if (entries.length === 0 || entries.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT + 1) {
51849
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP entry set is invalid', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51850
+ }
51851
+ const manifestEntry = zip.file('manifest.json');
51852
+ if (!manifestEntry) {
51853
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP has no manifest.json', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51854
+ }
51855
+ const manifestBinary = yield manifestEntry.async('arraybuffer');
51856
+ if (manifestBinary.byteLength <= 0 ||
51857
+ manifestBinary.byteLength > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES) {
51858
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource manifest size is invalid', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51859
+ }
51860
+ let manifestValue;
51861
+ try {
51862
+ manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
51863
+ }
51864
+ catch (error) {
51865
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource manifest is invalid: ${String(error)}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51866
+ }
51867
+ const manifest = parseProtocolV2ResourceManifest(manifestValue);
51868
+ const selectedFiles = selectProtocolV2ResourceManifestFiles({
51869
+ manifest,
51870
+ targetsToUpdate: (_a = this.params.targetsToUpdate) !== null && _a !== void 0 ? _a : [],
51871
+ });
51872
+ const expectedEntryNames = new Set([
51873
+ 'manifest.json',
51874
+ ...selectedFiles.map(file => file.archive_path),
51875
+ ]);
51876
+ if (entries.length !== expectedEntryNames.size ||
51877
+ entries.some(entry => !expectedEntryNames.has(entry.name))) {
51878
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP contains an unexpected entry', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51879
+ }
51880
+ let totalSize = 0;
51881
+ const resourceBundles = [];
51882
+ for (const [index, file] of selectedFiles.entries()) {
51883
+ const entry = zip.file(file.archive_path);
51884
+ if (!entry) {
51885
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource ZIP is missing ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51886
+ }
51887
+ const fileBinary = yield entry.async('arraybuffer');
51888
+ const digest = bytesToHex(sha256.sha256(new Uint8Array(fileBinary)));
51889
+ if (fileBinary.byteLength !== file.size || digest !== file.sha256.toLowerCase()) {
51890
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, `Protocol V2 local resource file does not match manifest: ${file.archive_path}`, { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' });
51891
+ }
51892
+ totalSize += fileBinary.byteLength;
51893
+ if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
51894
+ throw hdShared.ERRORS.TypedError(hdShared.HardwareErrorCode.RuntimeError, 'Protocol V2 local resource ZIP exceeds the total size limit', { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' });
51895
+ }
51896
+ const header = fileBinary.byteLength >= PROTOCOL_V2_OKPP_HEADER_SIZE
51897
+ ? parseProtocolV2OkppHeader(new Uint8Array(fileBinary))
51898
+ : null;
51899
+ resourceBundles.push(Object.assign({ name: file.original_name || `resource-${index}`, binary: fileBinary, devicePath: file.device_path }, (header
51900
+ ? {
51901
+ version: header.version,
51902
+ payloadHash: header.payloadHash,
51903
+ headerHash: header.headerHash,
51904
+ }
51905
+ : {})));
51906
+ }
51907
+ return resourceBundles;
51908
+ });
51909
+ }
51767
51910
  prepareProtocolV2ResourceSources() {
51768
51911
  var _a, _b;
51769
51912
  return __awaiter(this, void 0, void 0, function* () {
@@ -52416,7 +52559,7 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52416
52559
  });
52417
52560
  });
52418
52561
  }
52419
- executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, }) {
52562
+ executeProtocolV2Update({ fwBinaryMap, bootloaderBinary, installItems, resourceBundles = [], }) {
52420
52563
  return __awaiter(this, void 0, void 0, function* () {
52421
52564
  const memoryInstallItems = installItems !== null && installItems !== void 0 ? installItems : this.buildProtocolV2InstallItems({
52422
52565
  fwBinaryMap: fwBinaryMap !== null && fwBinaryMap !== void 0 ? fwBinaryMap : [],
@@ -52431,9 +52574,12 @@ class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod {
52431
52574
  kind: item.kind,
52432
52575
  });
52433
52576
  })));
52577
+ const resourceSources = yield Promise.all(resourceBundles.map((resource) => __awaiter(this, void 0, void 0, function* () {
52578
+ return (Object.assign(Object.assign(Object.assign({ name: resource.name, source: yield this.openProtocolV2MemorySource(resource.binary), devicePath: resource.devicePath }, (resource.version ? { version: resource.version } : {})), (resource.payloadHash ? { payloadHash: resource.payloadHash } : {})), (resource.headerHash ? { headerHash: resource.headerHash } : {})));
52579
+ })));
52434
52580
  return yield this.executeProtocolV2Phases({
52435
52581
  installSources,
52436
- resourceSources: [],
52582
+ resourceSources,
52437
52583
  });
52438
52584
  }
52439
52585
  finally {
@@ -65047,17 +65193,6 @@ const switchTransport = ({ env, Transport, plugin, }) => {
65047
65193
  };
65048
65194
 
65049
65195
  let memoryHostSequence = 0;
65050
- const FIRMWARE_UPDATE_V4_COMPONENT_TARGETS = new Set([
65051
- 'boot',
65052
- 'app_v1',
65053
- 'app_v2',
65054
- 'coprocessor',
65055
- 'se01',
65056
- 'se02',
65057
- 'se03',
65058
- 'se04',
65059
- ]);
65060
- const isFirmwareUpdateV4ComponentTarget = (target) => FIRMWARE_UPDATE_V4_COMPONENT_TARGETS.has(target);
65061
65196
  const createReference = (binary, prefix) => {
65062
65197
  const digest = utils.bytesToHex(sha256.sha256(new Uint8Array(binary)));
65063
65198
  return {
@@ -65126,23 +65261,9 @@ function prepareFirmwareUpdateV4MemoryHost({ sdk, plan, artifacts, }) {
65126
65261
  artifactReader,
65127
65262
  preparedPlanDigest: preparedPlan.preparedPlanDigest,
65128
65263
  });
65129
- const componentArtifacts = {};
65130
- const expectedTargetVersions = {};
65131
- for (const artifact of preparedPlan.artifacts) {
65132
- if (artifact.role === 'component' && isFirmwareUpdateV4ComponentTarget(artifact.target)) {
65133
- componentArtifacts[artifact.target] = artifact.artifact;
65134
- }
65135
- if (artifact.targetVersion) {
65136
- expectedTargetVersions[artifact.target] = artifact.targetVersion;
65137
- }
65138
- }
65139
65264
  return {
65140
65265
  preparedPlan,
65141
65266
  hostBindingGeneration,
65142
- targetsToUpdate: [...preparedPlan.targetsToUpdate],
65143
- expectedDeviceId: preparedPlan.deviceIdentity,
65144
- expectedTargetVersions,
65145
- componentArtifacts,
65146
65267
  release: () => {
65147
65268
  sdk.unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
65148
65269
  readers.clear();
@@ -113,6 +113,7 @@ export interface FirmwareUpdateV4Params {
113
113
  se02Binary?: ArrayBuffer;
114
114
  se03Binary?: ArrayBuffer;
115
115
  se04Binary?: ArrayBuffer;
116
+ resourceArchiveBinary?: ArrayBuffer;
116
117
  forcedUpdateRes?: boolean;
117
118
  artifactReader?: FirmwareArtifactReader;
118
119
  componentArtifacts?: Partial<Record<Exclude<FirmwareUpdateV4Target, 'resource'>, FirmwareArtifactReference>>;
@@ -1 +1 @@
1
- {"version":3,"file":"firmwareUpdate.d.ts","sourceRoot":"","sources":["../../../src/types/api/firmwareUpdate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAE/E,KAAK,WAAW,GAAG,UAAU,GAAG,KAAK,CAAC;AAEtC,MAAM,WAAW,yBAAyB;IACxC,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QAC5C,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,IAAI,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC;QACzE,IAAI,EAAE,WAAW,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,GAAG,EAAE,OAAO,CAAC;KACd,CAAC,CAAC;IACH,KAAK,CAAC,KAAK,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,yBAAyB;IACxC,cAAc,EAAE,sBAAsB,CAAC;IAEvC,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,0BAA0B;IACzC,MAAM,EAAE,WAAW,CAAC;IACpB,UAAU,EAAE,WAAW,CAAC;CACzB;AAED,MAAM,WAAW,4BAA4B;IAC3C,YAAY,EAAE,0BAA0B,CAAC;IACzC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,yBAAyB,CAAC;IACpC,eAAe,CAAC,EAAE,KAAK,CAAC;QACtB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,yBAAyB,CAAC;KACrC,CAAC,CAAC;IACH,UAAU,EAAE,WAAW,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,WAAW,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED,MAAM,CAAC,OAAO,UAAU,cAAc,CACpC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,CAAC,oBAAoB,CAAC,GAAG;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GACnE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAC3B,MAAM,CAAC,OAAO,UAAU,cAAc,CACpC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,CAAC,0BAA0B,CAAC,GAAG;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GACzE,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAE3B,KAAK,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK,GAAG,WAAW,CAAC;AACpE,KAAK,QAAQ,GAAG;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,CAAC;AAExC,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,CAAC,oBAAoB,GAAG,QAAQ,CAAC,GAC9C,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAC3B,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,CAAC,0BAA0B,GAAG,QAAQ,CAAC,GACpD,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAC3B,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,CAAC,4BAA4B,GAAG,QAAQ,CAAC,GACtD,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAE3B,MAAM,WAAW,sBAAsB;IACrC,YAAY,CAAC,EAAE,0BAA0B,CAAC;IAC1C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,SAAS,CAAC,EAAE,WAAW,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,cAAc,CAAC,EAAE,WAAW,CAAC;IAE7B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,gBAAgB,CAAC,EAAE,WAAW,CAAC;IAE/B,cAAc,CAAC,EAAE,WAAW,CAAC;IAC7B,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,YAAY,CAAC,EAAE,aAAa,CAAC;IAE7B,QAAQ,EAAE,SAAS,CAAC;IAEpB,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,SAAS,CAAC,EAAE;QACV,GAAG,CAAC,EAAE,yBAAyB,CAAC;QAChC,QAAQ,CAAC,EAAE,yBAAyB,CAAC;QACrC,UAAU,CAAC,EAAE,yBAAyB,CAAC;QACvC,eAAe,CAAC,EAAE,KAAK,CAAC;YACtB,SAAS,EAAE,MAAM,CAAC;YAClB,QAAQ,EAAE,yBAAyB,CAAC;SACrC,CAAC,CAAC;KACJ,CAAC;CACH;AAMD,MAAM,MAAM,sBAAsB,GAC9B,MAAM,GACN,QAAQ,GACR,QAAQ,GACR,aAAa,GACb,UAAU,GACV,MAAM,GACN,MAAM,GACN,MAAM,GACN,MAAM,CAAC;AAEX,MAAM,WAAW,sBAAsB;IACrC,YAAY,CAAC,EAAE,0BAA0B,CAAC;IAC1C,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,EAAE,SAAS,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,eAAe,CAAC,EAAE,sBAAsB,EAAE,CAAC;IAC3C,sBAAsB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC,CAAC;IAGzE,eAAe,CAAC,EAAE,WAAW,CAAC;IAE9B,gBAAgB,CAAC,EAAE,WAAW,CAAC;IAE/B,mBAAmB,CAAC,EAAE,WAAW,CAAC;IAElC,mBAAmB,CAAC,EAAE,WAAW,CAAC;IAElC,iBAAiB,CAAC,EAAE,WAAW,CAAC;IAEhC,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,kBAAkB,CAAC,EAAE,OAAO,CAC1B,MAAM,CAAC,OAAO,CAAC,sBAAsB,EAAE,UAAU,CAAC,EAAE,yBAAyB,CAAC,CAC/E,CAAC;CACH;AAED,MAAM,CAAC,OAAO,UAAU,iCAAiC,CACvD,OAAO,EAAE,yBAAyB,GACjC,MAAM,CAAC;AAEV,MAAM,CAAC,OAAO,UAAU,mCAAmC,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;AAE1F,MAAM,CAAC,OAAO,UAAU,sCAAsC,IAAI,MAAM,CAAC;AAEzE,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,CAAC,sBAAsB,CAAC,GACrC,QAAQ,CAAC;IACV,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC,CAAC;AAEH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CACtC,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,MAAM,EAAE,MAAM,CAAC,sBAAsB,CAAC,GACrC,QAAQ,CAAC;IACV,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC,CAAC"}
1
+ {"version":3,"file":"firmwareUpdate.d.ts","sourceRoot":"","sources":["../../../src/types/api/firmwareUpdate.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.87",
3
+ "version": "1.2.0-alpha.88",
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.87",
29
- "@onekeyfe/hd-transport": "1.2.0-alpha.87",
28
+ "@onekeyfe/hd-shared": "1.2.0-alpha.88",
29
+ "@onekeyfe/hd-transport": "1.2.0-alpha.88",
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": "4192396a9d3cf4930ce7d710752db898155a3293"
47
+ "gitHead": "004b8385657f82848f58fd91f25bd3d12d7e33c7"
48
48
  }
@@ -1,4 +1,5 @@
1
1
  import { EDeviceType, ERRORS, HardwareError, HardwareErrorCode, wait } from '@onekeyfe/hd-shared';
2
+ import JSZip from 'jszip';
2
3
  import {
3
4
  DeviceRebootType,
4
5
  PROTOCOL_V2_BLE_FILE_CHUNK_SIZE,
@@ -178,6 +179,10 @@ type ProtocolV2ResourceBundleSource = {
178
179
  headerHash?: string;
179
180
  };
180
181
 
182
+ type ProtocolV2ResourceBundleBinary = Omit<ProtocolV2ResourceBundleSource, 'source'> & {
183
+ binary: ArrayBuffer;
184
+ };
185
+
181
186
  type ProtocolV2ExecutionPhaseKind =
182
187
  | 'resource-sync'
183
188
  | 'bootloader-install'
@@ -270,6 +275,19 @@ const PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID = new Map<number, FirmwareUpdateV4T
270
275
  [ProtocolV2FirmwareTargetType.FW_MGMT_TARGET_SE04, 'se04'],
271
276
  ]);
272
277
 
278
+ const PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET = new Map<
279
+ Exclude<FirmwareUpdateV4Target, 'resource'>,
280
+ ProtocolV2RemoteComponentTarget
281
+ >(
282
+ Object.values(PROTOCOL_V2_REMOTE_COMPONENT_TARGETS).map(target => [
283
+ PROTOCOL_V2_UPDATE_TARGET_BY_TARGET_ID.get(target.targetId) as Exclude<
284
+ FirmwareUpdateV4Target,
285
+ 'resource'
286
+ >,
287
+ target,
288
+ ])
289
+ );
290
+
273
291
  const PROTOCOL_V2_ROMLOADER_UNSUPPORTED_MESSAGE =
274
292
  'FW_MGMT_TARGET_ROMLOADER is not accepted by the current Pro2 bootloader update request. Flash romloader with the loader-specific flow instead of firmwareUpdateV4.';
275
293
 
@@ -541,6 +559,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
541
559
  { name: 'se02Binary', type: 'buffer' },
542
560
  { name: 'se03Binary', type: 'buffer' },
543
561
  { name: 'se04Binary', type: 'buffer' },
562
+ { name: 'resourceArchiveBinary', type: 'buffer' },
544
563
  { name: 'firmwareType', type: 'string' },
545
564
  { name: 'targetsToUpdate', type: 'array', allowEmpty: true },
546
565
  { name: 'platform', type: 'string' },
@@ -558,6 +577,24 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
558
577
  const preparedPlan = payload.preparedPlan
559
578
  ? validateFirmwareUpdatePreparedPlan(payload.preparedPlan)
560
579
  : undefined;
580
+ const hasLocalArtifacts = [
581
+ payload.bootloaderBinary,
582
+ payload.romloaderBinary,
583
+ payload.applicationP1Binary,
584
+ payload.applicationP2Binary,
585
+ payload.coprocessorBinary,
586
+ payload.se01Binary,
587
+ payload.se02Binary,
588
+ payload.se03Binary,
589
+ payload.se04Binary,
590
+ payload.resourceArchiveBinary,
591
+ ].some(Boolean);
592
+ if (preparedPlan && hasLocalArtifacts) {
593
+ throw ERRORS.TypedError(
594
+ HardwareErrorCode.CallMethodInvalidParameter,
595
+ 'Prepared firmware plans cannot be combined with local firmware or resource binaries'
596
+ );
597
+ }
561
598
  const hostBinding =
562
599
  payload.hostBindingGeneration !== undefined
563
600
  ? resolveFirmwareUpdateHostBinding(
@@ -566,29 +603,53 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
566
603
  )
567
604
  : undefined;
568
605
  if (preparedPlan) {
569
- const componentArtifacts = (payload.componentArtifacts ?? {}) as NonNullable<
570
- FirmwareUpdateV4Params['componentArtifacts']
571
- >;
572
606
  assertFirmwareUpdatePreparedPlanBinding({
573
607
  preparedPlan,
574
608
  executor: 'v4',
575
609
  platform: payload.platform,
576
- scopeTargets: ['boot', 'app_v1', 'app_v2', 'coprocessor', 'se01', 'se02', 'se03', 'se04'],
577
- bindings: [
578
- ...Object.entries(componentArtifacts).flatMap(([target, artifact]) =>
579
- artifact
580
- ? [
581
- {
582
- target: target as Exclude<FirmwareUpdateV4Target, 'resource'>,
583
- artifact,
584
- },
585
- ]
586
- : []
587
- ),
588
- ],
610
+ scopeTargets: [],
611
+ bindings: [],
589
612
  });
613
+ if (payload.componentArtifacts) {
614
+ const componentBindings: Array<{
615
+ target: Exclude<FirmwareUpdateV4Target, 'resource'>;
616
+ artifact: FirmwareArtifactReference;
617
+ }> = Object.entries(payload.componentArtifacts).flatMap(([target, artifact]) =>
618
+ artifact
619
+ ? [
620
+ {
621
+ target: target as Exclude<FirmwareUpdateV4Target, 'resource'>,
622
+ artifact: artifact as FirmwareArtifactReference,
623
+ },
624
+ ]
625
+ : []
626
+ );
627
+ assertFirmwareUpdatePreparedPlanBinding({
628
+ preparedPlan,
629
+ executor: 'v4',
630
+ platform: payload.platform,
631
+ scopeTargets: componentBindings.map(binding => binding.target),
632
+ bindings: componentBindings,
633
+ });
634
+ }
590
635
  }
591
636
 
637
+ const preparedExpectedTargetVersions = preparedPlan?.artifacts.reduce<
638
+ NonNullable<FirmwareUpdateV4Params['expectedTargetVersions']>
639
+ >((result, artifact) => {
640
+ if (
641
+ artifact.role === 'component' &&
642
+ artifact.target !== 'resource' &&
643
+ artifact.targetVersion &&
644
+ PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET.has(
645
+ artifact.target as Exclude<FirmwareUpdateV4Target, 'resource'>
646
+ )
647
+ ) {
648
+ result[artifact.target as FirmwareUpdateV4Target] = artifact.targetVersion;
649
+ }
650
+ return result;
651
+ }, {});
652
+
592
653
  this.params = {
593
654
  preparedPlan,
594
655
  chunkSize: payload.chunkSize,
@@ -602,13 +663,18 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
602
663
  se02Binary: payload.se02Binary,
603
664
  se03Binary: payload.se03Binary,
604
665
  se04Binary: payload.se04Binary,
605
- firmwareType: payload.firmwareType,
606
- targetsToUpdate: payload.targetsToUpdate,
607
- expectedTargetVersions: payload.expectedTargetVersions,
666
+ resourceArchiveBinary: payload.resourceArchiveBinary,
667
+ firmwareType: preparedPlan?.firmwareType ?? payload.firmwareType,
668
+ targetsToUpdate: preparedPlan
669
+ ? ([...preparedPlan.targetsToUpdate] as FirmwareUpdateV4Target[])
670
+ : payload.targetsToUpdate,
671
+ expectedTargetVersions: preparedPlan
672
+ ? preparedExpectedTargetVersions
673
+ : payload.expectedTargetVersions,
608
674
  platform: payload.platform,
609
675
  expectedDeviceId: payload.expectedDeviceId,
610
676
  artifactReader: hostBinding?.artifactReader ?? payload.artifactReader,
611
- componentArtifacts: payload.componentArtifacts,
677
+ componentArtifacts: preparedPlan ? undefined : payload.componentArtifacts,
612
678
  };
613
679
  }
614
680
 
@@ -665,6 +731,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
665
731
  let fwBinaryMap: ProtocolV2TargetBinary[] = [];
666
732
  let bootloaderBinary: ArrayBuffer | null = null;
667
733
  let installItems: ProtocolV2InstallItem[] | undefined;
734
+ let resourceBundles: ProtocolV2ResourceBundleBinary[] = [];
668
735
  try {
669
736
  this.postTipMessage(FirmwareUpdateTipMessage.StartDownloadFirmware);
670
737
  fwBinaryMap = this.collectExplicitTargetBinaries();
@@ -678,12 +745,17 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
678
745
  ? missingFirmwareTargets.length > 0
679
746
  : explicitInstallItems.length === 0;
680
747
  if (wantsResources) {
681
- throw ERRORS.TypedError(
682
- HardwareErrorCode.RuntimeError,
683
- 'Protocol V2 resource manifest must be prepared by the external firmware host',
684
- {
685
- firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
686
- }
748
+ if (!this.params.resourceArchiveBinary) {
749
+ throw ERRORS.TypedError(
750
+ HardwareErrorCode.RuntimeError,
751
+ 'Protocol V2 resource archive must be provided for a local resource update',
752
+ {
753
+ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
754
+ }
755
+ );
756
+ }
757
+ resourceBundles = await this.prepareProtocolV2LocalResourceArchive(
758
+ this.params.resourceArchiveBinary
687
759
  );
688
760
  }
689
761
  if (
@@ -729,7 +801,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
729
801
  throw normalizeFirmwarePreparationError(err);
730
802
  }
731
803
 
732
- if (!bootloaderBinary && fwBinaryMap.length === 0 && !installItems?.length) {
804
+ if (
805
+ !bootloaderBinary &&
806
+ fwBinaryMap.length === 0 &&
807
+ !installItems?.length &&
808
+ resourceBundles.length === 0
809
+ ) {
733
810
  throw ERRORS.TypedError(
734
811
  HardwareErrorCode.FirmwareUpdateDownloadFailed,
735
812
  'No firmware to update'
@@ -740,6 +817,7 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
740
817
  fwBinaryMap,
741
818
  bootloaderBinary,
742
819
  ...(installItems ? { installItems } : undefined),
820
+ ...(resourceBundles.length > 0 ? { resourceBundles } : undefined),
743
821
  });
744
822
  }
745
823
 
@@ -782,6 +860,54 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
782
860
  firmwareType: EFirmwareType,
783
861
  features: Features
784
862
  ): Promise<ProtocolV2InstallSource[]> {
863
+ if (this.params.preparedPlan) {
864
+ const requestedTargets = new Set(
865
+ this.params.preparedPlan.targetsToUpdate.filter(
866
+ (target): target is Exclude<FirmwareUpdateV4Target, 'resource'> => target !== 'resource'
867
+ )
868
+ );
869
+ const installSources: ProtocolV2InstallSource[] = [];
870
+ const preparedTargets = new Set<Exclude<FirmwareUpdateV4Target, 'resource'>>();
871
+ for (const artifact of this.params.preparedPlan.artifacts) {
872
+ if (artifact.target !== 'resource') {
873
+ const target = artifact.target as Exclude<FirmwareUpdateV4Target, 'resource'>;
874
+ const installTarget = PROTOCOL_V2_INSTALL_TARGET_BY_UPDATE_TARGET.get(target);
875
+ if (
876
+ !requestedTargets.has(target) ||
877
+ artifact.role !== 'component' ||
878
+ artifact.container !== 'raw' ||
879
+ !installTarget ||
880
+ preparedTargets.has(target)
881
+ ) {
882
+ throw ERRORS.TypedError(
883
+ HardwareErrorCode.RuntimeError,
884
+ `Protocol V2 prepared component artifact is invalid: ${artifact.artifactId}`,
885
+ { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
886
+ );
887
+ }
888
+ installSources.push({
889
+ ...installTarget,
890
+ source: await this.openProtocolV2PreparedSource(artifact.artifact),
891
+ });
892
+ preparedTargets.add(target);
893
+ }
894
+ }
895
+ const missingTarget = Array.from(requestedTargets).find(
896
+ target => !preparedTargets.has(target)
897
+ );
898
+ if (missingTarget) {
899
+ throw ERRORS.TypedError(
900
+ HardwareErrorCode.RuntimeError,
901
+ `Protocol V2 ${missingTarget} artifact is not prepared`,
902
+ {
903
+ firmwareUpdateCode: 'FirmwareArtifactsNotPrepared',
904
+ artifactName: missingTarget,
905
+ }
906
+ );
907
+ }
908
+ return installSources;
909
+ }
910
+
785
911
  const release = DataManager.getFirmwareLatestRelease(features, firmwareType);
786
912
  if (!release) {
787
913
  throw ERRORS.TypedError(
@@ -831,6 +957,116 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
831
957
  return installSources;
832
958
  }
833
959
 
960
+ private async prepareProtocolV2LocalResourceArchive(
961
+ binary: ArrayBuffer
962
+ ): Promise<ProtocolV2ResourceBundleBinary[]> {
963
+ const zip = await JSZip.loadAsync(binary);
964
+ const entries = Object.values(zip.files).filter(entry => !entry.dir);
965
+ if (entries.length === 0 || entries.length > PROTOCOL_V2_RESOURCE_FILE_MAX_COUNT + 1) {
966
+ throw ERRORS.TypedError(
967
+ HardwareErrorCode.RuntimeError,
968
+ 'Protocol V2 local resource ZIP entry set is invalid',
969
+ { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
970
+ );
971
+ }
972
+ const manifestEntry = zip.file('manifest.json');
973
+ if (!manifestEntry) {
974
+ throw ERRORS.TypedError(
975
+ HardwareErrorCode.RuntimeError,
976
+ 'Protocol V2 local resource ZIP has no manifest.json',
977
+ { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
978
+ );
979
+ }
980
+ const manifestBinary = await manifestEntry.async('arraybuffer');
981
+ if (
982
+ manifestBinary.byteLength <= 0 ||
983
+ manifestBinary.byteLength > PROTOCOL_V2_RESOURCE_MANIFEST_MAX_BYTES
984
+ ) {
985
+ throw ERRORS.TypedError(
986
+ HardwareErrorCode.RuntimeError,
987
+ 'Protocol V2 local resource manifest size is invalid',
988
+ { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
989
+ );
990
+ }
991
+
992
+ let manifestValue: unknown;
993
+ try {
994
+ manifestValue = JSON.parse(new TextDecoder().decode(manifestBinary));
995
+ } catch (error) {
996
+ throw ERRORS.TypedError(
997
+ HardwareErrorCode.RuntimeError,
998
+ `Protocol V2 local resource manifest is invalid: ${String(error)}`,
999
+ { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
1000
+ );
1001
+ }
1002
+ const manifest = parseProtocolV2ResourceManifest(manifestValue);
1003
+ const selectedFiles = selectProtocolV2ResourceManifestFiles({
1004
+ manifest,
1005
+ targetsToUpdate: this.params.targetsToUpdate ?? [],
1006
+ });
1007
+ const expectedEntryNames = new Set([
1008
+ 'manifest.json',
1009
+ ...selectedFiles.map(file => file.archive_path),
1010
+ ]);
1011
+ if (
1012
+ entries.length !== expectedEntryNames.size ||
1013
+ entries.some(entry => !expectedEntryNames.has(entry.name))
1014
+ ) {
1015
+ throw ERRORS.TypedError(
1016
+ HardwareErrorCode.RuntimeError,
1017
+ 'Protocol V2 local resource ZIP contains an unexpected entry',
1018
+ { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
1019
+ );
1020
+ }
1021
+
1022
+ let totalSize = 0;
1023
+ const resourceBundles: ProtocolV2ResourceBundleBinary[] = [];
1024
+ for (const [index, file] of selectedFiles.entries()) {
1025
+ const entry = zip.file(file.archive_path);
1026
+ if (!entry) {
1027
+ throw ERRORS.TypedError(
1028
+ HardwareErrorCode.RuntimeError,
1029
+ `Protocol V2 local resource ZIP is missing ${file.archive_path}`,
1030
+ { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
1031
+ );
1032
+ }
1033
+ const fileBinary = await entry.async('arraybuffer');
1034
+ const digest = bytesToHex(sha256(new Uint8Array(fileBinary)));
1035
+ if (fileBinary.byteLength !== file.size || digest !== file.sha256.toLowerCase()) {
1036
+ throw ERRORS.TypedError(
1037
+ HardwareErrorCode.RuntimeError,
1038
+ `Protocol V2 local resource file does not match manifest: ${file.archive_path}`,
1039
+ { firmwareUpdateCode: 'FirmwareArtifactReceiptMismatch' }
1040
+ );
1041
+ }
1042
+ totalSize += fileBinary.byteLength;
1043
+ if (totalSize > PROTOCOL_V2_RESOURCE_TOTAL_MAX_BYTES) {
1044
+ throw ERRORS.TypedError(
1045
+ HardwareErrorCode.RuntimeError,
1046
+ 'Protocol V2 local resource ZIP exceeds the total size limit',
1047
+ { firmwareUpdateCode: 'FirmwareArtifactsNotPrepared' }
1048
+ );
1049
+ }
1050
+ const header =
1051
+ fileBinary.byteLength >= PROTOCOL_V2_OKPP_HEADER_SIZE
1052
+ ? parseProtocolV2OkppHeader(new Uint8Array(fileBinary))
1053
+ : null;
1054
+ resourceBundles.push({
1055
+ name: file.original_name || `resource-${index}`,
1056
+ binary: fileBinary,
1057
+ devicePath: file.device_path,
1058
+ ...(header
1059
+ ? {
1060
+ version: header.version,
1061
+ payloadHash: header.payloadHash,
1062
+ headerHash: header.headerHash,
1063
+ }
1064
+ : {}),
1065
+ });
1066
+ }
1067
+ return resourceBundles;
1068
+ }
1069
+
834
1070
  private async prepareProtocolV2ResourceSources(): Promise<ProtocolV2ResourceBundleSource[]> {
835
1071
  const resourceRequested = this.params.targetsToUpdate?.includes('resource') ?? false;
836
1072
  if (!resourceRequested) {
@@ -1672,10 +1908,12 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1672
1908
  fwBinaryMap,
1673
1909
  bootloaderBinary,
1674
1910
  installItems,
1911
+ resourceBundles = [],
1675
1912
  }: {
1676
1913
  fwBinaryMap?: ProtocolV2TargetBinary[];
1677
1914
  bootloaderBinary?: ArrayBuffer | null;
1678
1915
  installItems?: ProtocolV2InstallItem[];
1916
+ resourceBundles?: ProtocolV2ResourceBundleBinary[];
1679
1917
  }) {
1680
1918
  const memoryInstallItems =
1681
1919
  installItems ??
@@ -1692,9 +1930,19 @@ export default class FirmwareUpdateV4 extends FirmwareUpdateBaseMethod<FirmwareU
1692
1930
  kind: item.kind,
1693
1931
  }))
1694
1932
  );
1933
+ const resourceSources = await Promise.all(
1934
+ resourceBundles.map(async resource => ({
1935
+ name: resource.name,
1936
+ source: await this.openProtocolV2MemorySource(resource.binary),
1937
+ devicePath: resource.devicePath,
1938
+ ...(resource.version ? { version: resource.version } : {}),
1939
+ ...(resource.payloadHash ? { payloadHash: resource.payloadHash } : {}),
1940
+ ...(resource.headerHash ? { headerHash: resource.headerHash } : {}),
1941
+ }))
1942
+ );
1695
1943
  return await this.executeProtocolV2Phases({
1696
1944
  installSources,
1697
- resourceSources: [],
1945
+ resourceSources,
1698
1946
  });
1699
1947
  } finally {
1700
1948
  await this.closeProtocolV2PreparedSources();
@@ -6,7 +6,6 @@ import type { CoreApi } from '../../types/api';
6
6
  import type {
7
7
  FirmwareArtifactReader,
8
8
  FirmwareArtifactReference,
9
- FirmwareUpdateV4Target,
10
9
  } from '../../types/api/firmwareUpdate';
11
10
  import type { FirmwareUpdatePlan } from '../../types/api/firmwareUpdatePlan';
12
11
 
@@ -24,33 +23,11 @@ export type FirmwareMemoryArtifact = {
24
23
  export type FirmwareUpdateV4MemoryHost = {
25
24
  preparedPlan: ReturnType<CoreApi['prepareFirmwareUpdatePlan']>;
26
25
  hostBindingGeneration: number;
27
- targetsToUpdate: FirmwareUpdateV4Target[];
28
- expectedDeviceId: string;
29
- expectedTargetVersions: Partial<Record<FirmwareUpdateV4Target, string>>;
30
- componentArtifacts: Partial<
31
- Record<Exclude<FirmwareUpdateV4Target, 'resource'>, FirmwareArtifactReference>
32
- >;
33
26
  release: () => void;
34
27
  };
35
28
 
36
29
  let memoryHostSequence = 0;
37
30
 
38
- const FIRMWARE_UPDATE_V4_COMPONENT_TARGETS = new Set<Exclude<FirmwareUpdateV4Target, 'resource'>>([
39
- 'boot',
40
- 'app_v1',
41
- 'app_v2',
42
- 'coprocessor',
43
- 'se01',
44
- 'se02',
45
- 'se03',
46
- 'se04',
47
- ]);
48
-
49
- const isFirmwareUpdateV4ComponentTarget = (
50
- target: string
51
- ): target is Exclude<FirmwareUpdateV4Target, 'resource'> =>
52
- FIRMWARE_UPDATE_V4_COMPONENT_TARGETS.has(target as Exclude<FirmwareUpdateV4Target, 'resource'>);
53
-
54
31
  const createReference = (binary: ArrayBuffer, prefix: string): FirmwareArtifactReference => {
55
32
  const digest = bytesToHex(sha256(new Uint8Array(binary)));
56
33
  return {
@@ -148,23 +125,9 @@ export function prepareFirmwareUpdateV4MemoryHost({
148
125
  artifactReader,
149
126
  preparedPlanDigest: preparedPlan.preparedPlanDigest,
150
127
  });
151
- const componentArtifacts: FirmwareUpdateV4MemoryHost['componentArtifacts'] = {};
152
- const expectedTargetVersions: FirmwareUpdateV4MemoryHost['expectedTargetVersions'] = {};
153
- for (const artifact of preparedPlan.artifacts) {
154
- if (artifact.role === 'component' && isFirmwareUpdateV4ComponentTarget(artifact.target)) {
155
- componentArtifacts[artifact.target] = artifact.artifact;
156
- }
157
- if (artifact.targetVersion) {
158
- expectedTargetVersions[artifact.target as FirmwareUpdateV4Target] = artifact.targetVersion;
159
- }
160
- }
161
128
  return {
162
129
  preparedPlan,
163
130
  hostBindingGeneration,
164
- targetsToUpdate: [...preparedPlan.targetsToUpdate] as FirmwareUpdateV4Target[],
165
- expectedDeviceId: preparedPlan.deviceIdentity,
166
- expectedTargetVersions,
167
- componentArtifacts,
168
131
  release: () => {
169
132
  sdk.unregisterFirmwareUpdateHostBinding(hostBindingGeneration);
170
133
  readers.clear();
@@ -154,6 +154,8 @@ export interface FirmwareUpdateV4Params {
154
154
  se02Binary?: ArrayBuffer;
155
155
  se03Binary?: ArrayBuffer;
156
156
  se04Binary?: ArrayBuffer;
157
+ /** Complete Protocol V2 resource ZIP for local development; never bound to a remote Plan. */
158
+ resourceArchiveBinary?: ArrayBuffer;
157
159
  forcedUpdateRes?: boolean;
158
160
  artifactReader?: FirmwareArtifactReader;
159
161
  componentArtifacts?: Partial<