@onekeyfe/hd-core 0.0.9 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/api/BaseMethod.d.ts +2 -0
  2. package/dist/api/BaseMethod.d.ts.map +1 -1
  3. package/dist/api/CheckBLEFirmwareRelease.d.ts +8 -1
  4. package/dist/api/CheckBLEFirmwareRelease.d.ts.map +1 -1
  5. package/dist/api/CheckFirmwareRelease.d.ts +8 -1
  6. package/dist/api/CheckFirmwareRelease.d.ts.map +1 -1
  7. package/dist/api/FirmwareUpdate.d.ts +14 -0
  8. package/dist/api/FirmwareUpdate.d.ts.map +1 -0
  9. package/dist/api/firmware/getBinary.d.ts +33 -0
  10. package/dist/api/firmware/getBinary.d.ts.map +1 -0
  11. package/dist/api/firmware/uploadFirmware.d.ts +8 -0
  12. package/dist/api/firmware/uploadFirmware.d.ts.map +1 -0
  13. package/dist/api/index.d.ts +1 -0
  14. package/dist/api/index.d.ts.map +1 -1
  15. package/dist/api/stellar/StellarSignTransaction.d.ts +1 -1
  16. package/dist/constants/errors.d.ts +1 -0
  17. package/dist/constants/errors.d.ts.map +1 -1
  18. package/dist/core/index.d.ts.map +1 -1
  19. package/dist/data-manager/DataManager.d.ts +10 -0
  20. package/dist/data-manager/DataManager.d.ts.map +1 -1
  21. package/dist/device/Device.d.ts +1 -0
  22. package/dist/device/Device.d.ts.map +1 -1
  23. package/dist/device/DeviceCommands.d.ts +1 -0
  24. package/dist/device/DeviceCommands.d.ts.map +1 -1
  25. package/dist/events/ui-request.d.ts +9 -1
  26. package/dist/events/ui-request.d.ts.map +1 -1
  27. package/dist/index.d.ts +95 -6
  28. package/dist/index.js +190 -23
  29. package/dist/inject.d.ts.map +1 -1
  30. package/dist/types/api/checkBLEFirmwareRelease.d.ts +12 -2
  31. package/dist/types/api/checkBLEFirmwareRelease.d.ts.map +1 -1
  32. package/dist/types/api/checkFirmwareRelease.d.ts +11 -1
  33. package/dist/types/api/checkFirmwareRelease.d.ts.map +1 -1
  34. package/dist/types/api/firmwareUpdate.d.ts +13 -0
  35. package/dist/types/api/firmwareUpdate.d.ts.map +1 -0
  36. package/dist/types/api/index.d.ts +2 -0
  37. package/dist/types/api/index.d.ts.map +1 -1
  38. package/dist/types/device.d.ts +38 -0
  39. package/dist/types/device.d.ts.map +1 -1
  40. package/dist/types/firmware.d.ts +2 -1
  41. package/dist/types/firmware.d.ts.map +1 -1
  42. package/dist/types/params.d.ts +3 -0
  43. package/dist/types/params.d.ts.map +1 -1
  44. package/dist/utils/assets.d.ts +1 -1
  45. package/dist/utils/assets.d.ts.map +1 -1
  46. package/dist/utils/networkUtils.d.ts.map +1 -1
  47. package/dist/utils/release.d.ts +4 -0
  48. package/dist/utils/release.d.ts.map +1 -0
  49. package/package.json +3 -3
  50. package/src/api/BaseMethod.ts +4 -0
  51. package/src/api/CheckBLEFirmwareRelease.ts +7 -1
  52. package/src/api/CheckFirmwareRelease.ts +7 -1
  53. package/src/api/FirmwareUpdate.ts +78 -0
  54. package/src/api/firmware/getBinary.ts +46 -0
  55. package/src/api/firmware/uploadFirmware.ts +72 -0
  56. package/src/api/index.ts +2 -0
  57. package/src/constants/errors.ts +1 -0
  58. package/src/core/index.ts +1 -0
  59. package/src/data-manager/DataManager.ts +36 -20
  60. package/src/device/Device.ts +4 -0
  61. package/src/device/DeviceCommands.ts +2 -0
  62. package/src/events/ui-request.ts +15 -1
  63. package/src/inject.ts +2 -0
  64. package/src/types/api/checkBLEFirmwareRelease.ts +12 -4
  65. package/src/types/api/checkFirmwareRelease.ts +11 -1
  66. package/src/types/api/firmwareUpdate.ts +21 -0
  67. package/src/types/api/index.ts +3 -0
  68. package/src/types/device.ts +44 -0
  69. package/src/types/firmware.ts +2 -1
  70. package/src/types/params.ts +2 -0
  71. package/src/utils/assets.ts +1 -1
  72. package/src/utils/networkUtils.ts +3 -1
  73. package/src/utils/release.ts +24 -0
@@ -0,0 +1,78 @@
1
+ import { ERRORS } from '../constants';
2
+ import { UI_REQUEST } from '../constants/ui-request';
3
+ import { BaseMethod } from './BaseMethod';
4
+ import { validateParams } from './helpers/paramsValidator';
5
+ import { getBinary } from './firmware/getBinary';
6
+ import { uploadFirmware } from './firmware/uploadFirmware';
7
+
8
+ type Params = {
9
+ binary?: ArrayBuffer;
10
+ version?: number[];
11
+ updateType: 'firmware' | 'ble';
12
+ };
13
+
14
+ export default class FirmwareUpdate extends BaseMethod<Params> {
15
+ init() {
16
+ this.allowDeviceMode = [UI_REQUEST.BOOTLOADER, UI_REQUEST.INITIALIZE];
17
+ this.requireDeviceMode = [UI_REQUEST.BOOTLOADER];
18
+
19
+ const { payload } = this;
20
+
21
+ validateParams(payload, [
22
+ { name: 'version', type: 'array' },
23
+ { name: 'binary', type: 'buffer' },
24
+ ]);
25
+
26
+ if (!payload.updateType) {
27
+ throw ERRORS.TypedError('Method_InvalidParameter', 'updateType is required');
28
+ }
29
+
30
+ this.params = { updateType: payload.updateType };
31
+
32
+ if ('version' in payload) {
33
+ this.params = {
34
+ ...this.params,
35
+ version: payload.version,
36
+ };
37
+ }
38
+
39
+ if ('binary' in payload) {
40
+ this.params = {
41
+ ...this.params,
42
+ binary: payload.binary,
43
+ };
44
+ }
45
+ }
46
+
47
+ async run() {
48
+ const { device, params } = this;
49
+
50
+ let binary;
51
+
52
+ try {
53
+ if (params.binary) {
54
+ binary = this.params.binary;
55
+ } else {
56
+ if (!device.features) {
57
+ throw ERRORS.TypedError('Runtime', 'no features found for this device');
58
+ }
59
+ const firmware = await getBinary({
60
+ features: device.features,
61
+ version: params.version,
62
+ updateType: params.updateType,
63
+ });
64
+ binary = firmware.binary;
65
+ }
66
+ } catch (err) {
67
+ throw ERRORS.TypedError('Method_FirmwareUpdate_DownloadFailed', err);
68
+ }
69
+
70
+ return uploadFirmware(
71
+ params.updateType,
72
+ this.device.getCommands().typedCall.bind(this.device.getCommands()),
73
+ this.postMessage,
74
+ device,
75
+ { payload: binary }
76
+ );
77
+ }
78
+ }
@@ -0,0 +1,46 @@
1
+ import semver from 'semver';
2
+ import { Features } from '../../types';
3
+ import { getDeviceType, httpRequest } from '../../utils';
4
+ import { DataManager } from '../../data-manager';
5
+ import { ERRORS } from '../../constants';
6
+
7
+ export interface GetInfoProps {
8
+ features: Features;
9
+ updateType: 'firmware' | 'ble';
10
+ }
11
+
12
+ interface GetBinaryProps extends GetInfoProps {
13
+ version?: number[];
14
+ }
15
+
16
+ export const getBinary = async ({ features, updateType, version }: GetBinaryProps) => {
17
+ const releaseInfo = getInfo({ features, updateType });
18
+
19
+ if (!releaseInfo) {
20
+ throw ERRORS.TypedError('Runtime', 'no firmware found for this device');
21
+ }
22
+
23
+ if (
24
+ version &&
25
+ !semver.eq(releaseInfo.version as unknown as semver.SemVer, version as unknown as semver.SemVer)
26
+ ) {
27
+ throw ERRORS.TypedError('Runtime', 'firmware version mismatch');
28
+ }
29
+
30
+ // @ts-expect-error
31
+ const url = updateType === 'ble' ? releaseInfo.webUpdate : releaseInfo.url;
32
+ const fw = await httpRequest(url, 'binary');
33
+
34
+ return {
35
+ ...releaseInfo,
36
+ binary: fw,
37
+ };
38
+ };
39
+
40
+ const getInfo = ({ features, updateType }: GetInfoProps) => {
41
+ const deviceType = getDeviceType(features);
42
+ const { deviceMap } = DataManager;
43
+ const releaseInfo = deviceMap?.[deviceType]?.[updateType]?.[0] ?? null;
44
+
45
+ return releaseInfo;
46
+ };
@@ -0,0 +1,72 @@
1
+ import { DEVICE, CoreMessage, createUiMessage, UI_REQUEST } from '../../events';
2
+ import { ERRORS, PROTO } from '../../constants';
3
+ import type { Device } from '../../device/Device';
4
+ import type { TypedCall } from '../../device/DeviceCommands';
5
+ import { KnownDevice } from '../../types';
6
+
7
+ const postConfirmationMessage = (device: Device) => {
8
+ // only if firmware is already installed. fresh device does not require button confirmation
9
+ if (device.features?.firmware_present) {
10
+ device.emit(DEVICE.BUTTON, device, { code: 'ButtonRequest_FirmwareUpdate' });
11
+ }
12
+ };
13
+
14
+ const postProgressMessage = (
15
+ device: Device,
16
+ progress: number,
17
+ postMessage: (message: CoreMessage) => void
18
+ ) => {
19
+ postMessage(
20
+ createUiMessage(UI_REQUEST.FIRMWARE_PROGRESS, {
21
+ device: device.toMessageObject() as KnownDevice,
22
+ progress,
23
+ })
24
+ );
25
+ };
26
+
27
+ export const uploadFirmware = async (
28
+ updateType: 'firmware' | 'ble',
29
+ typedCall: TypedCall,
30
+ postMessage: (message: CoreMessage) => void,
31
+ device: Device,
32
+ { payload }: PROTO.FirmwareUpload
33
+ ) => {
34
+ if (device.features?.major_version === 1) {
35
+ postConfirmationMessage(device);
36
+ const eraseCommand = updateType === 'firmware' ? 'FirmwareErase' : 'FirmwareErase_ex';
37
+ await typedCall(eraseCommand as unknown as any, 'Success', {});
38
+ postProgressMessage(device, 0, postMessage);
39
+ const { message } = await typedCall('FirmwareUpload', 'Success', {
40
+ payload,
41
+ });
42
+
43
+ return message;
44
+ }
45
+
46
+ if (device.features?.major_version === 2) {
47
+ postConfirmationMessage(device);
48
+ const length = payload.byteLength;
49
+
50
+ let response = await typedCall('FirmwareErase', ['FirmwareRequest', 'Success'], { length });
51
+ while (response.type !== 'Success') {
52
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
53
+ const start = response.message.offset!;
54
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
55
+ const end = response.message.offset! + response.message.length!;
56
+ const chunk = payload.slice(start, end);
57
+
58
+ if (start > 0) {
59
+ postProgressMessage(device, Math.round((start / length) * 100), postMessage);
60
+ }
61
+
62
+ response = await typedCall('FirmwareUpload', ['FirmwareRequest', 'Success'], {
63
+ payload: chunk,
64
+ });
65
+ }
66
+
67
+ postProgressMessage(device, 100, postMessage);
68
+ return response.message;
69
+ }
70
+
71
+ throw ERRORS.TypedError('Runtime', 'uploadFirmware: unknown major_version');
72
+ };
package/src/api/index.ts CHANGED
@@ -39,3 +39,5 @@ export { default as solSignTransaction } from './solana/SolSignTransaction';
39
39
 
40
40
  export { default as stellarGetAddress } from './stellar/StellarGetAddress';
41
41
  export { default as stellarSignTransaction } from './stellar/StellarSignTransaction';
42
+
43
+ export { default as firmwareUpdate } from './FirmwareUpdate';
@@ -3,6 +3,7 @@ export const ERROR_CODES = {
3
3
  Method_InvalidParameter: '',
4
4
  Call_API: '',
5
5
  Call_NotResponse: 'No response data',
6
+ Method_FirmwareUpdate_DownloadFailed: '',
6
7
 
7
8
  // device error
8
9
  Transport_InvalidProtobuf: '',
package/src/core/index.ts CHANGED
@@ -57,6 +57,7 @@ export const callAPI = async (message: CoreMessage) => {
57
57
  try {
58
58
  method = findMethod(message as IFrameCallMessage);
59
59
  method.connector = _connector;
60
+ method.postMessage = postMessage;
60
61
  method.init();
61
62
  } catch (error) {
62
63
  return Promise.reject(error);
@@ -18,6 +18,7 @@ import type {
18
18
  IDeviceBLEFirmwareStatus,
19
19
  ITransportStatus,
20
20
  } from '../types';
21
+ import { getReleaseChangelog, getReleaseStatus } from '../utils/release';
21
22
 
22
23
  export default class DataManager {
23
24
  static deviceMap: DeviceTypeMap = {
@@ -59,21 +60,30 @@ export default class DataManager {
59
60
  }
60
61
 
61
62
  const targetDeviceConfigList = this.deviceMap[deviceType]?.firmware ?? [];
62
- const latestFirmware = targetDeviceConfigList[targetDeviceConfigList.length - 1];
63
-
64
- if (!latestFirmware) return 'valid';
65
-
66
- const latestVersion = latestFirmware.version.join('.');
67
63
  const currentVersion = deviceFirmwareVersion.join('.');
64
+ return getReleaseStatus(targetDeviceConfigList, currentVersion);
65
+ };
68
66
 
69
- /** latest is greater or equal current */
70
- if (semver.gt(latestVersion, currentVersion)) {
71
- if (latestFirmware.required) return 'required';
67
+ static getFirmwareChangelog = (features: Features) => {
68
+ const deviceType = getDeviceType(features);
69
+ const deviceFirmwareVersion = getDeviceFirmwareVersion(features);
72
70
 
73
- return 'outdated';
71
+ if (
72
+ features.firmware_present === false ||
73
+ (deviceType === 'classic' && features.bootloader_mode)
74
+ ) {
75
+ return [];
74
76
  }
75
77
 
76
- return 'valid';
78
+ const targetDeviceConfigList = this.deviceMap[deviceType]?.firmware ?? [];
79
+ const currentVersion = deviceFirmwareVersion.join('.');
80
+ return getReleaseChangelog(targetDeviceConfigList, currentVersion);
81
+ };
82
+
83
+ static getFirmwareLeatestRelease = (features: Features) => {
84
+ const deviceType = getDeviceType(features);
85
+ const targetDeviceConfigList = this.deviceMap[deviceType]?.firmware ?? [];
86
+ return targetDeviceConfigList[targetDeviceConfigList.length - 1];
77
87
  };
78
88
 
79
89
  static getBLEFirmwareStatus = (features: Features): IDeviceBLEFirmwareStatus => {
@@ -86,21 +96,27 @@ export default class DataManager {
86
96
  }
87
97
 
88
98
  const targetDeviceConfigList = this.deviceMap[deviceType]?.ble ?? [];
89
- const latestBLEFirmware = targetDeviceConfigList[targetDeviceConfigList.length - 1];
90
-
91
- if (!latestBLEFirmware) return 'valid';
92
-
93
- const latestVersion = latestBLEFirmware.version.join('.');
94
99
  const currentVersion = deviceBLEFirmwareVersion.join('.');
100
+ return getReleaseStatus(targetDeviceConfigList, currentVersion);
101
+ };
95
102
 
96
- /** latest is greater or equal current */
97
- if (semver.gt(latestVersion, currentVersion)) {
98
- if (latestBLEFirmware.required) return 'required';
103
+ static getBleFirmwareChangelog = (features: Features) => {
104
+ const deviceType = getDeviceType(features);
105
+ const deviceBLEFirmwareVersion = getDeviceBLEFirmwareVersion(features);
99
106
 
100
- return 'outdated';
107
+ if (!deviceBLEFirmwareVersion) {
108
+ return [];
101
109
  }
102
110
 
103
- return 'valid';
111
+ const targetDeviceConfigList = this.deviceMap[deviceType]?.ble ?? [];
112
+ const currentVersion = deviceBLEFirmwareVersion.join('.');
113
+ return getReleaseChangelog(targetDeviceConfigList, currentVersion);
114
+ };
115
+
116
+ static getBleFirmwareLeatestRelease = (features: Features) => {
117
+ const deviceType = getDeviceType(features);
118
+ const targetDeviceConfigList = this.deviceMap[deviceType]?.ble ?? [];
119
+ return targetDeviceConfigList[targetDeviceConfigList.length - 1];
104
120
  };
105
121
 
106
122
  static getTransportStatus = (localVersion: string): ITransportStatus => {
@@ -225,6 +225,10 @@ export class Device extends EventEmitter {
225
225
  }
226
226
  }
227
227
 
228
+ getCommands() {
229
+ return this.commands;
230
+ }
231
+
228
232
  getInternalState() {
229
233
  return this.internalState[this.instance];
230
234
  }
@@ -205,3 +205,5 @@ export class DeviceCommands {
205
205
  });
206
206
  }
207
207
  }
208
+
209
+ export type TypedCall = DeviceCommands['typedCall'];
@@ -14,6 +14,8 @@ export const UI_REQUEST = {
14
14
 
15
15
  BLUETOOTH_PERMISSION: 'ui-bluetooth_permission',
16
16
  LOCATION_PERMISSION: 'ui-location_permission',
17
+
18
+ FIRMWARE_PROGRESS: 'ui-firmware-progress',
17
19
  } as const;
18
20
 
19
21
  export interface UiRequestWithoutPayload {
@@ -37,7 +39,19 @@ export interface UiRequestButton {
37
39
  payload: DeviceButtonRequest['payload'];
38
40
  }
39
41
 
40
- export type UiEvent = UiRequestWithoutPayload | UiRequestDeviceAction | UiRequestButton;
42
+ export interface FirmwareProgress {
43
+ type: typeof UI_REQUEST.FIRMWARE_PROGRESS;
44
+ payload: {
45
+ device: Device;
46
+ progress: number;
47
+ };
48
+ }
49
+
50
+ export type UiEvent =
51
+ | UiRequestWithoutPayload
52
+ | UiRequestDeviceAction
53
+ | UiRequestButton
54
+ | FirmwareProgress;
41
55
 
42
56
  export type UiEventMessage = UiEvent & { event: typeof UI_EVENT };
43
57
 
package/src/inject.ts CHANGED
@@ -124,6 +124,8 @@ export const inject = ({
124
124
  call({ ...params, connectId, method: 'stellarGetAddress' }),
125
125
  stellarSignTransaction: (connectId, params) =>
126
126
  call({ ...params, connectId, method: 'stellarSignTransaction' }),
127
+
128
+ firmwareUpdate: (connectId, params) => call({ ...params, connectId, method: 'firmwareUpdate' }),
127
129
  };
128
130
  return api;
129
131
  };
@@ -1,6 +1,14 @@
1
1
  import type { Response } from '../params';
2
- import type { IDeviceFirmwareStatus } from '../device';
2
+ import type { IDeviceBLEFirmwareStatus } from '../device';
3
+ import { IBLEFirmwareReleaseInfo } from '../settings';
3
4
 
4
- export declare function checkBLEFirmwareRelease(
5
- connectId?: string
6
- ): Response<IDeviceFirmwareStatus>;
5
+ type BleFirmwareRelease = {
6
+ status: IDeviceBLEFirmwareStatus;
7
+ changelog: {
8
+ 'zh-CN': string;
9
+ 'en-US': string;
10
+ }[];
11
+ release: IBLEFirmwareReleaseInfo;
12
+ };
13
+
14
+ export declare function checkBLEFirmwareRelease(connectId?: string): Response<BleFirmwareRelease>;
@@ -1,4 +1,14 @@
1
1
  import type { Response } from '../params';
2
2
  import type { IDeviceFirmwareStatus } from '../device';
3
+ import { IFirmwareReleaseInfo } from '../settings';
3
4
 
4
- export declare function checkFirmwareRelease(connectId?: string): Response<IDeviceFirmwareStatus>;
5
+ type FirmwareRelease = {
6
+ status: IDeviceFirmwareStatus;
7
+ changelog: {
8
+ 'en-US': string;
9
+ 'zh-CN': string;
10
+ }[];
11
+ release: IFirmwareReleaseInfo;
12
+ };
13
+
14
+ export declare function checkFirmwareRelease(connectId?: string): Response<FirmwareRelease>;
@@ -0,0 +1,21 @@
1
+ import type { PROTO } from '../../constants';
2
+ import type { Params, Response } from '../params';
3
+
4
+ export interface FirmwareUpdateBinary {
5
+ binary: ArrayBuffer;
6
+ }
7
+
8
+ export interface FirmwareUpdate {
9
+ version: number[];
10
+ btcOnly?: boolean;
11
+ updateType: 'firmware' | 'ble';
12
+ }
13
+
14
+ export declare function firmwareUpdate(
15
+ connectId: string | undefined,
16
+ params: Params<FirmwareUpdate>
17
+ ): Response<PROTO.Success>;
18
+ export declare function firmwareUpdate(
19
+ connectId: string | undefined,
20
+ params: Params<FirmwareUpdateBinary>
21
+ ): Response<PROTO.Success>;
@@ -39,6 +39,7 @@ import { solSignTransaction } from './solSignTransaction';
39
39
  import { stellarGetAddress } from './stellarGetAddress';
40
40
  import { stellarSignTransaction } from './stellarSignTransaction';
41
41
  import { cipherKeyValue } from './cipherKeyValue';
42
+ import { firmwareUpdate } from './firmwareUpdate';
42
43
 
43
44
  export * from './export';
44
45
 
@@ -108,4 +109,6 @@ export type CoreApi = {
108
109
 
109
110
  stellarGetAddress: typeof stellarGetAddress;
110
111
  stellarSignTransaction: typeof stellarSignTransaction;
112
+
113
+ firmwareUpdate: typeof firmwareUpdate;
111
114
  };
@@ -86,3 +86,47 @@ export type ITransportStatus = 'valid' | 'outdated';
86
86
  export type DeviceFirmwareRange = {
87
87
  [deviceType in IDeviceType | IDeviceModel]?: { min: string; max?: string };
88
88
  };
89
+
90
+ type FeaturesNarrowing =
91
+ | {
92
+ major_version: 2;
93
+ fw_major: null;
94
+ fw_minor: null;
95
+ fw_patch: null;
96
+ bootloader_mode: true;
97
+ firmware_present: false;
98
+ }
99
+ | {
100
+ major_version: 2;
101
+ fw_major: null;
102
+ fw_minor: null;
103
+ fw_patch: null;
104
+ bootloader_mode: null;
105
+ firmware_present: null;
106
+ }
107
+ | {
108
+ major_version: 2;
109
+ fw_major: 2;
110
+ fw_minor: number;
111
+ fw_patch: number;
112
+ bootloader_mode: true;
113
+ firmware_present: true;
114
+ }
115
+ | {
116
+ major_version: 1;
117
+ fw_major: null;
118
+ fw_minor: null;
119
+ fw_patch: null;
120
+ bootloader_mode: true;
121
+ firmware_present: false;
122
+ }
123
+ | {
124
+ major_version: 1;
125
+ fw_major: null;
126
+ fw_minor: null;
127
+ fw_patch: null;
128
+ bootloader_mode: true;
129
+ firmware_present: true;
130
+ };
131
+
132
+ export type StrictFeatures = Features & FeaturesNarrowing;
@@ -9,7 +9,8 @@ export interface FirmwareRange {
9
9
  };
10
10
  }
11
11
 
12
- export type VersionArray = [1 | 2, number, number];
12
+ export type MajorVersion = 1 | 2;
13
+ export type VersionArray = [MajorVersion, number, number];
13
14
 
14
15
  export type FirmwareRelease = {
15
16
  required: boolean;
@@ -2,6 +2,8 @@ export interface CommonParams {
2
2
  keepSession?: boolean;
3
3
  }
4
4
 
5
+ export type Params<T> = CommonParams & T & { bundle?: undefined };
6
+
5
7
  export interface Unsuccessful {
6
8
  success: false;
7
9
  payload: { error: string; code?: string };
@@ -1,5 +1,5 @@
1
1
  import { httpRequest as browserHttpRequest } from './networkUtils';
2
2
 
3
- export const httpRequest = (url: string, _type: string): any => browserHttpRequest(url);
3
+ export const httpRequest = (url: string, type: string): any => browserHttpRequest(url, type);
4
4
 
5
5
  export const getTimeStamp = () => new Date().getTime();
@@ -4,13 +4,15 @@ export const httpRequest = async (url: string, type = 'text') => {
4
4
  const response = await axios.request({
5
5
  url,
6
6
  withCredentials: false,
7
+ responseType: type === 'binary' ? 'arraybuffer' : 'json',
7
8
  });
9
+
8
10
  if (+response.status === 200) {
9
11
  if (type === 'json') {
10
12
  return response.data;
11
13
  }
12
14
  if (type === 'binary') {
13
- return response.data.arrayBuffer();
15
+ return response.data;
14
16
  }
15
17
  return response.data;
16
18
  }
@@ -0,0 +1,24 @@
1
+ import semver from 'semver';
2
+ import { IBLEFirmwareReleaseInfo, IDeviceFirmwareStatus, IFirmwareReleaseInfo } from '../types';
3
+
4
+ export const getReleaseStatus = (
5
+ releases: (IFirmwareReleaseInfo | IBLEFirmwareReleaseInfo)[],
6
+ currentVersion: string
7
+ ): IDeviceFirmwareStatus => {
8
+ const newVersions = releases.filter(r => semver.gt(r.version.join('.'), currentVersion));
9
+ if (newVersions.length === 0) {
10
+ return 'valid';
11
+ }
12
+ if (newVersions.some(r => r.required)) {
13
+ return 'required';
14
+ }
15
+ return 'outdated';
16
+ };
17
+
18
+ export const getReleaseChangelog = (
19
+ releases: (IFirmwareReleaseInfo | IBLEFirmwareReleaseInfo)[],
20
+ currentVersion: string
21
+ ): IFirmwareReleaseInfo['changelog'][] => {
22
+ const newVersions = releases.filter(r => semver.gt(r.version.join('.'), currentVersion));
23
+ return newVersions.map(r => r.changelog);
24
+ };