@onekeyfe/hd-core 1.2.0-alpha.37 → 1.2.0-alpha.39

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.
@@ -0,0 +1,74 @@
1
+ import { createUiMessage } from '../src/events';
2
+ import { UI_REQUEST } from '../src/events/ui-request';
3
+ import { createUiProgressMessageFilter } from '../src/utils/uiProgressThrottle';
4
+
5
+ import type { KnownDevice } from '../src/types';
6
+
7
+ describe('createUiProgressMessageFilter', () => {
8
+ let currentTime: number;
9
+ let shouldPostMessage: ReturnType<typeof createUiProgressMessageFilter>;
10
+
11
+ beforeEach(() => {
12
+ currentTime = 1_000;
13
+ shouldPostMessage = createUiProgressMessageFilter(250, () => currentTime);
14
+ });
15
+
16
+ const firmwareProgress = (
17
+ progress: number,
18
+ progressType: 'transferData' | 'installingFirmware' = 'transferData'
19
+ ) =>
20
+ createUiMessage(UI_REQUEST.FIRMWARE_PROGRESS, {
21
+ device: {} as KnownDevice,
22
+ progress,
23
+ progressType,
24
+ });
25
+
26
+ test('limits firmware progress to one event per interval', () => {
27
+ expect(shouldPostMessage(firmwareProgress(1))).toBe(true);
28
+
29
+ currentTime += 100;
30
+ expect(shouldPostMessage(firmwareProgress(1))).toBe(false);
31
+
32
+ currentTime += 150;
33
+ expect(shouldPostMessage(firmwareProgress(1))).toBe(true);
34
+ });
35
+
36
+ test('limits transfer and install progress independently', () => {
37
+ expect(shouldPostMessage(firmwareProgress(1, 'transferData'))).toBe(true);
38
+ expect(shouldPostMessage(firmwareProgress(1, 'installingFirmware'))).toBe(true);
39
+
40
+ currentTime += 10;
41
+ expect(shouldPostMessage(firmwareProgress(2, 'transferData'))).toBe(false);
42
+ expect(shouldPostMessage(firmwareProgress(2, 'installingFirmware'))).toBe(false);
43
+ });
44
+
45
+ test('emits phase boundaries immediately and suppresses duplicate boundaries', () => {
46
+ expect(shouldPostMessage(firmwareProgress(0))).toBe(true);
47
+ expect(shouldPostMessage(firmwareProgress(0))).toBe(false);
48
+
49
+ currentTime += 10;
50
+ expect(shouldPostMessage(firmwareProgress(50))).toBe(false);
51
+ expect(shouldPostMessage(firmwareProgress(100))).toBe(true);
52
+ expect(shouldPostMessage(firmwareProgress(100))).toBe(false);
53
+
54
+ expect(shouldPostMessage(firmwareProgress(0))).toBe(true);
55
+ });
56
+
57
+ test('treats decreasing progress as a new phase', () => {
58
+ expect(shouldPostMessage(firmwareProgress(80))).toBe(true);
59
+
60
+ currentTime += 10;
61
+ expect(shouldPostMessage(firmwareProgress(20))).toBe(true);
62
+ });
63
+
64
+ test('also limits device progress and leaves other UI events unchanged', () => {
65
+ const deviceProgress = (progress: number) =>
66
+ createUiMessage(UI_REQUEST.DEVICE_PROGRESS, { progress });
67
+
68
+ expect(shouldPostMessage(deviceProgress(1))).toBe(true);
69
+ currentTime += 10;
70
+ expect(shouldPostMessage(deviceProgress(2))).toBe(false);
71
+
72
+ expect(shouldPostMessage(createUiMessage(UI_REQUEST.CLOSE_UI_WINDOW))).toBe(true);
73
+ });
74
+ });
@@ -7,7 +7,6 @@ import type { Deferred } from '@onekeyfe/hd-shared';
7
7
  import type { TypedResponseMessage } from '../../device/DeviceCommands';
8
8
  export declare class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
9
9
  checkPromise: Deferred<any> | null;
10
- private shouldPostFirmwareProgress;
11
10
  init(): void;
12
11
  run(): Promise<any>;
13
12
  isBleReconnect(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"FirmwareUpdateBaseMethod.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwareUpdateBaseMethod.ts"],"names":[],"mappings":";AAaA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,OAAO,KAAK,EACV,2BAA2B,EAC3B,yBAAyB,EAC1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAexE,qBAAa,wBAAwB,CAAC,MAAM,CAAE,SAAQ,UAAU,CAAC,MAAM,CAAC;IACtE,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAE1C,OAAO,CAAC,0BAA0B,CAAoC;IAEtE,IAAI,IAAI,IAAI;IAEZ,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IAInB,cAAc,IAAI,OAAO;IASzB,cAAc,YAAa,yBAAyB,UASlD;IAMF,qBAAqB,SAAU,UAAU,GAAG,KAAK,GAAG,YAAY,GAAG,UAAU,UAM3E;IAMF,mBAAmB,aAAc,MAAM,gBAAgB,2BAA2B,UAYhF;cAEc,qCAAqC;cAkBrC,uCAAuC;IAkBvD,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS;YA0FvC,4BAA4B;IAuBpC,mBAAmB;IA8CnB,uBAAuB,CAAC,EAAE,IAAI,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IA6BlD,8BAA8B,CAAC,IAAI,EAAE,MAAM;IAW3C,uBAAuB,CAAC,EAC5B,OAAO,EACP,QAAQ,EACR,aAAa,EACb,SAAS,GACV,EAAE,KAAK,CAAC,cAAc,GAAG;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;IA4CK,sBAAsB,CAC1B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,WAAW,GAAG,MAAM,EAC3B,SAAS,EAAE,OAAO,EAClB,QAAQ,EAAE,MAAM,GAAG,IAAI;IAwEnB,MAAM,CAAC,UAAU,EAAE,UAAU;CAsBpC"}
1
+ {"version":3,"file":"FirmwareUpdateBaseMethod.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/FirmwareUpdateBaseMethod.ts"],"names":[],"mappings":";AAaA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,OAAO,KAAK,EACV,2BAA2B,EAC3B,yBAAyB,EAC1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAexE,qBAAa,wBAAwB,CAAC,MAAM,CAAE,SAAQ,UAAU,CAAC,MAAM,CAAC;IACtE,YAAY,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,IAAI,CAAQ;IAE1C,IAAI,IAAI,IAAI;IAEZ,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IAInB,cAAc,IAAI,OAAO;IASzB,cAAc,YAAa,yBAAyB,UASlD;IAMF,qBAAqB,SAAU,UAAU,GAAG,KAAK,GAAG,YAAY,GAAG,UAAU,UAM3E;IAMF,mBAAmB,aAAc,MAAM,gBAAgB,2BAA2B,UAQhF;cAEc,qCAAqC;cAkBrC,uCAAuC;IAkBvD,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS;YA0FvC,4BAA4B;IAuBpC,mBAAmB;IA8CnB,uBAAuB,CAAC,EAAE,IAAI,EAAE,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE;IA6BlD,8BAA8B,CAAC,IAAI,EAAE,MAAM;IAW3C,uBAAuB,CAAC,EAC5B,OAAO,EACP,QAAQ,EACR,aAAa,EACb,SAAS,GACV,EAAE,KAAK,CAAC,cAAc,GAAG;QACxB,QAAQ,EAAE,MAAM,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB;IA4CK,sBAAsB,CAC1B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,WAAW,GAAG,MAAM,EAC3B,SAAS,EAAE,OAAO,EAClB,QAAQ,EAAE,MAAM,GAAG,IAAI;IAwEnB,MAAM,CAAC,UAAU,EAAE,UAAU;CAsBpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AA8BlC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAsB1C,OAAO,eAAe,MAAM,2BAA2B,CAAC;AAUxD,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,UAAU,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAmD,MAAM,WAAW,CAAC;AAI9F,OAAO,KAAK,EACV,6BAA6B,EAG9B,MAAM,wBAAwB,CAAC;AAWhC,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AA+D7D,eAAO,MAAM,OAAO,YAAmB,WAAW,WAAW,WAAW,iBA+EvE,CAAC;AAg1BF,eAAO,MAAM,MAAM,YAAa,WAAW,cAAc,MAAM,SAkF9D,CAAC;AA6FF,eAAO,MAAM,qBAAqB,gFAejC,CAAC;AAgKF,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,YAAY;IAC5C,OAAO,CAAC,cAAc,CAAoB;IAE1C,SAAgB,aAAa,EAAE,MAAM,CAAC;IAEtC,OAAO,CAAC,YAAY,CAAsB;IAE1C,OAAO,CAAC,cAAc,CAAC,CAAgB;IAGvC,OAAO,CAAC,qBAAqB,CAA4B;IAEzD,OAAO,CAAC,iBAAiB,CAAoB;;IAS7C,OAAO,CAAC,cAAc;IAoBhB,aAAa,CAAC,OAAO,EAAE,WAAW;IAkExC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAOV,gBAAgB;CAiC/B;AAED,eAAO,MAAM,QAAQ,YAIpB,CAAC;AAEF,eAAO,MAAM,aAAa,uBAYzB,CAAC;AAMF,eAAO,MAAM,IAAI,aACL,eAAe,aACd,GAAG,WACL,6BAA6B,8BAoBvC,CAAC;AAEF,eAAO,MAAM,eAAe;SAKrB,eAAe,CAAC,KAAK,CAAC;eAChB,GAAG;;UASf,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":";AACA,OAAO,YAAY,MAAM,QAAQ,CAAC;AA8BlC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAsB1C,OAAO,eAAe,MAAM,2BAA2B,CAAC;AAWxD,OAAO,KAAK,EAAE,eAAe,EAAyB,MAAM,UAAU,CAAC;AACvE,OAAO,KAAK,EAAE,WAAW,EAAmD,MAAM,WAAW,CAAC;AAI9F,OAAO,KAAK,EACV,6BAA6B,EAG9B,MAAM,wBAAwB,CAAC;AAWhC,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;AA+D7D,eAAO,MAAM,OAAO,YAAmB,WAAW,WAAW,WAAW,iBAoFvE,CAAC;AAg1BF,eAAO,MAAM,MAAM,YAAa,WAAW,cAAc,MAAM,SAkF9D,CAAC;AA6FF,eAAO,MAAM,qBAAqB,gFAejC,CAAC;AAgKF,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,YAAY;IAC5C,OAAO,CAAC,cAAc,CAAoB;IAE1C,SAAgB,aAAa,EAAE,MAAM,CAAC;IAEtC,OAAO,CAAC,YAAY,CAAsB;IAE1C,OAAO,CAAC,cAAc,CAAC,CAAgB;IAGvC,OAAO,CAAC,qBAAqB,CAA4B;IAEzD,OAAO,CAAC,iBAAiB,CAAoB;;IAS7C,OAAO,CAAC,cAAc;IAoBhB,aAAa,CAAC,OAAO,EAAE,WAAW;IAkExC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;YAOV,gBAAgB;CAiC/B;AAED,eAAO,MAAM,QAAQ,YAIpB,CAAC;AAEF,eAAO,MAAM,aAAa,uBAYzB,CAAC;AAMF,eAAO,MAAM,IAAI,aACL,eAAe,aACd,GAAG,WACL,6BAA6B,8BAoBvC,CAAC;AAEF,eAAO,MAAM,eAAe;SAKrB,eAAe,CAAC,KAAK,CAAC;eAChB,GAAG;;UASf,CAAC"}
package/dist/index.js CHANGED
@@ -47192,35 +47192,6 @@ class DeviceFullyUploadResource extends BaseMethod {
47192
47192
  }
47193
47193
  }
47194
47194
 
47195
- const DEFAULT_FIRMWARE_PROGRESS_INTERVAL_MS = 250;
47196
- const createFirmwareProgressThrottle = (intervalMs = DEFAULT_FIRMWARE_PROGRESS_INTERVAL_MS) => {
47197
- const stateByType = new Map();
47198
- return (progress, progressType) => {
47199
- if (progressType !== 'transferData') {
47200
- return true;
47201
- }
47202
- const normalizedProgress = Math.max(0, Math.min(100, Math.floor(progress)));
47203
- if (normalizedProgress === 0 || normalizedProgress === 100) {
47204
- stateByType.set(progressType, {
47205
- lastEmittedAt: Date.now(),
47206
- lastProgress: normalizedProgress,
47207
- });
47208
- return true;
47209
- }
47210
- const now = Date.now();
47211
- const state = stateByType.get(progressType);
47212
- if (state &&
47213
- (state.lastProgress === normalizedProgress || now - state.lastEmittedAt < intervalMs)) {
47214
- return false;
47215
- }
47216
- stateByType.set(progressType, {
47217
- lastEmittedAt: now,
47218
- lastProgress: normalizedProgress,
47219
- });
47220
- return true;
47221
- };
47222
- };
47223
-
47224
47195
  const Log$9 = getLogger(exports.LoggerNames.Method);
47225
47196
  const SESSION_ERROR$1 = 'session not found';
47226
47197
  const FIRMWARE_UPDATE_CONFIRM = 'Firmware install confirmed';
@@ -47234,7 +47205,6 @@ class FirmwareUpdateBaseMethod extends BaseMethod {
47234
47205
  constructor() {
47235
47206
  super(...arguments);
47236
47207
  this.checkPromise = null;
47237
- this.shouldPostFirmwareProgress = createFirmwareProgressThrottle();
47238
47208
  this.postTipMessage = (message) => {
47239
47209
  this.postMessage(createUiMessage(UI_REQUEST.FIRMWARE_TIP, {
47240
47210
  device: this.device.toMessageObject(),
@@ -47249,9 +47219,6 @@ class FirmwareUpdateBaseMethod extends BaseMethod {
47249
47219
  }));
47250
47220
  };
47251
47221
  this.postProgressMessage = (progress, progressType) => {
47252
- if (!this.shouldPostFirmwareProgress(progress, progressType)) {
47253
- return;
47254
- }
47255
47222
  this.postMessage(createUiMessage(UI_REQUEST.FIRMWARE_PROGRESS, {
47256
47223
  device: this.device.toMessageObject(),
47257
47224
  progress,
@@ -60644,6 +60611,44 @@ const getSynchronize = (mutex) => {
60644
60611
  return (action, lockId) => lock(lockId).then(unlock => Promise.resolve().then(action).finally(unlock));
60645
60612
  };
60646
60613
 
60614
+ const DEFAULT_UI_PROGRESS_INTERVAL_MS = 250;
60615
+ const normalizeProgress = (progress) => {
60616
+ if (typeof progress !== 'number' || !Number.isFinite(progress)) {
60617
+ return undefined;
60618
+ }
60619
+ return Math.max(0, Math.min(100, Math.floor(progress)));
60620
+ };
60621
+ const createUiProgressMessageFilter = (intervalMs = DEFAULT_UI_PROGRESS_INTERVAL_MS, now = Date.now) => {
60622
+ const stateByType = new Map();
60623
+ return (message) => {
60624
+ if (!('event' in message) ||
60625
+ message.event !== UI_EVENT ||
60626
+ (message.type !== UI_REQUEST.DEVICE_PROGRESS && message.type !== UI_REQUEST.FIRMWARE_PROGRESS)) {
60627
+ return true;
60628
+ }
60629
+ const key = message.type === UI_REQUEST.FIRMWARE_PROGRESS
60630
+ ? `${message.type}:${message.payload.progressType}`
60631
+ : message.type;
60632
+ const progress = normalizeProgress(message.payload.progress);
60633
+ const currentTime = now();
60634
+ const state = stateByType.get(key);
60635
+ if (!state) {
60636
+ stateByType.set(key, { lastEmittedAt: currentTime, lastProgress: progress });
60637
+ return true;
60638
+ }
60639
+ const isBoundary = progress === 0 || progress === 100;
60640
+ if (isBoundary && progress === state.lastProgress) {
60641
+ return false;
60642
+ }
60643
+ const startsNewPhase = progress !== undefined && state.lastProgress !== undefined && progress < state.lastProgress;
60644
+ if (!isBoundary && !startsNewPhase && currentTime - state.lastEmittedAt < intervalMs) {
60645
+ return false;
60646
+ }
60647
+ stateByType.set(key, { lastEmittedAt: currentTime, lastProgress: progress });
60648
+ return true;
60649
+ };
60650
+ };
60651
+
60647
60652
  const Log = getLogger(exports.LoggerNames.Core);
60648
60653
  const PRE_INITIALIZE_TTL_MS = 60 * 1000;
60649
60654
  const preWarmInflight = new Map();
@@ -60709,7 +60714,12 @@ const callAPI = (context, message) => __awaiter(void 0, void 0, void 0, function
60709
60714
  try {
60710
60715
  method = findMethod(message);
60711
60716
  method.connector = _connector;
60712
- method.postMessage = postMessage;
60717
+ const shouldPostMessage = createUiProgressMessageFilter();
60718
+ method.postMessage = event => {
60719
+ if (shouldPostMessage(event)) {
60720
+ postMessage(event);
60721
+ }
60722
+ };
60713
60723
  (_a = method.setContext) === null || _a === void 0 ? void 0 : _a.call(method, context);
60714
60724
  method.requestContext = createRequestContext(method.responseID, method.name, {
60715
60725
  sdkInstanceId: context.sdkInstanceId,
@@ -0,0 +1,3 @@
1
+ import type { CoreMessage } from '../events';
2
+ export declare const createUiProgressMessageFilter: (intervalMs?: number, now?: () => number) => (message: CoreMessage) => boolean;
3
+ //# sourceMappingURL=uiProgressThrottle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uiProgressThrottle.d.ts","sourceRoot":"","sources":["../../src/utils/uiProgressThrottle.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAiB7C,eAAO,MAAM,6BAA6B,yDAMvB,WAAW,YAqC7B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onekeyfe/hd-core",
3
- "version": "1.2.0-alpha.37",
3
+ "version": "1.2.0-alpha.39",
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.37",
29
- "@onekeyfe/hd-transport": "1.2.0-alpha.37",
28
+ "@onekeyfe/hd-shared": "1.2.0-alpha.39",
29
+ "@onekeyfe/hd-transport": "1.2.0-alpha.39",
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": "af7d87f4136ea4ce3cbec3546e4ad52a3f5c0e1f"
47
+ "gitHead": "2cb8f692689327fc7e77cb848223cbeaa740dcad"
48
48
  }
@@ -13,7 +13,6 @@ import { DeviceModelToTypes } from '../../types';
13
13
  import { DataManager } from '../../data-manager';
14
14
  import { BaseMethod } from '../BaseMethod';
15
15
  import { DEVICE } from '../../events';
16
- import { createFirmwareProgressThrottle } from './progressThrottle';
17
16
 
18
17
  import type {
19
18
  IFirmwareUpdateProgressType,
@@ -41,8 +40,6 @@ const isDeviceDisconnectedError = (error: unknown) => {
41
40
  export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
42
41
  checkPromise: Deferred<any> | null = null;
43
42
 
44
- private shouldPostFirmwareProgress = createFirmwareProgressThrottle();
45
-
46
43
  init(): void {}
47
44
 
48
45
  run(): Promise<any> {
@@ -86,10 +83,6 @@ export class FirmwareUpdateBaseMethod<Params> extends BaseMethod<Params> {
86
83
  * @param progress Post the percentage of the progress
87
84
  */
88
85
  postProgressMessage = (progress: number, progressType: IFirmwareUpdateProgressType) => {
89
- if (!this.shouldPostFirmwareProgress(progress, progressType)) {
90
- return;
91
- }
92
-
93
86
  this.postMessage(
94
87
  createUiMessage(UI_REQUEST.FIRMWARE_PROGRESS, {
95
88
  device: this.device.toMessageObject() as KnownDevice,
package/src/core/index.ts CHANGED
@@ -60,6 +60,7 @@ import {
60
60
  ProtocolV2UiInteractionCoordinator,
61
61
  isProtocolV2UiEnabled,
62
62
  } from '../protocols/protocol-v2/uiInteraction';
63
+ import { createUiProgressMessageFilter } from '../utils/uiProgressThrottle';
63
64
 
64
65
  import type { ConnectSettings, Features, KnownDevice } from '../types';
65
66
  import type { CoreMessage, IFrameCallMessage, UiPromise, UiPromiseResponse } from '../events';
@@ -154,7 +155,12 @@ export const callAPI = async (context: CoreContext, message: CoreMessage) => {
154
155
  try {
155
156
  method = findMethod(message as IFrameCallMessage);
156
157
  method.connector = _connector;
157
- method.postMessage = postMessage;
158
+ const shouldPostMessage = createUiProgressMessageFilter();
159
+ method.postMessage = event => {
160
+ if (shouldPostMessage(event)) {
161
+ postMessage(event);
162
+ }
163
+ };
158
164
  method.setContext?.(context);
159
165
 
160
166
  method.requestContext = createRequestContext(method.responseID, method.name, {
@@ -0,0 +1,63 @@
1
+ import { UI_EVENT, UI_REQUEST } from '../events/ui-request';
2
+
3
+ import type { CoreMessage } from '../events';
4
+
5
+ const DEFAULT_UI_PROGRESS_INTERVAL_MS = 250;
6
+
7
+ type UiProgressThrottleState = {
8
+ lastEmittedAt: number;
9
+ lastProgress?: number;
10
+ };
11
+
12
+ const normalizeProgress = (progress: unknown) => {
13
+ if (typeof progress !== 'number' || !Number.isFinite(progress)) {
14
+ return undefined;
15
+ }
16
+
17
+ return Math.max(0, Math.min(100, Math.floor(progress)));
18
+ };
19
+
20
+ export const createUiProgressMessageFilter = (
21
+ intervalMs = DEFAULT_UI_PROGRESS_INTERVAL_MS,
22
+ now = Date.now
23
+ ) => {
24
+ const stateByType = new Map<string, UiProgressThrottleState>();
25
+
26
+ return (message: CoreMessage) => {
27
+ if (
28
+ !('event' in message) ||
29
+ message.event !== UI_EVENT ||
30
+ (message.type !== UI_REQUEST.DEVICE_PROGRESS && message.type !== UI_REQUEST.FIRMWARE_PROGRESS)
31
+ ) {
32
+ return true;
33
+ }
34
+
35
+ const key =
36
+ message.type === UI_REQUEST.FIRMWARE_PROGRESS
37
+ ? `${message.type}:${message.payload.progressType}`
38
+ : message.type;
39
+ const progress = normalizeProgress(message.payload.progress);
40
+ const currentTime = now();
41
+ const state = stateByType.get(key);
42
+
43
+ if (!state) {
44
+ stateByType.set(key, { lastEmittedAt: currentTime, lastProgress: progress });
45
+ return true;
46
+ }
47
+
48
+ const isBoundary = progress === 0 || progress === 100;
49
+ if (isBoundary && progress === state.lastProgress) {
50
+ return false;
51
+ }
52
+
53
+ const startsNewPhase =
54
+ progress !== undefined && state.lastProgress !== undefined && progress < state.lastProgress;
55
+
56
+ if (!isBoundary && !startsNewPhase && currentTime - state.lastEmittedAt < intervalMs) {
57
+ return false;
58
+ }
59
+
60
+ stateByType.set(key, { lastEmittedAt: currentTime, lastProgress: progress });
61
+ return true;
62
+ };
63
+ };
@@ -1,3 +0,0 @@
1
- import type { IFirmwareUpdateProgressType } from '../../events/ui-request';
2
- export declare const createFirmwareProgressThrottle: (intervalMs?: number) => (progress: number, progressType: IFirmwareUpdateProgressType) => boolean;
3
- //# sourceMappingURL=progressThrottle.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"progressThrottle.d.ts","sourceRoot":"","sources":["../../../src/api/firmware/progressThrottle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAS3E,eAAO,MAAM,8BAA8B,sCAKvB,MAAM,gBAAgB,2BAA2B,YA6BpE,CAAC"}
@@ -1,44 +0,0 @@
1
- import type { IFirmwareUpdateProgressType } from '../../events/ui-request';
2
-
3
- const DEFAULT_FIRMWARE_PROGRESS_INTERVAL_MS = 250;
4
-
5
- type FirmwareProgressThrottleState = {
6
- lastEmittedAt: number;
7
- lastProgress?: number;
8
- };
9
-
10
- export const createFirmwareProgressThrottle = (
11
- intervalMs = DEFAULT_FIRMWARE_PROGRESS_INTERVAL_MS
12
- ) => {
13
- const stateByType = new Map<IFirmwareUpdateProgressType, FirmwareProgressThrottleState>();
14
-
15
- return (progress: number, progressType: IFirmwareUpdateProgressType) => {
16
- if (progressType !== 'transferData') {
17
- return true;
18
- }
19
-
20
- const normalizedProgress = Math.max(0, Math.min(100, Math.floor(progress)));
21
- if (normalizedProgress === 0 || normalizedProgress === 100) {
22
- stateByType.set(progressType, {
23
- lastEmittedAt: Date.now(),
24
- lastProgress: normalizedProgress,
25
- });
26
- return true;
27
- }
28
-
29
- const now = Date.now();
30
- const state = stateByType.get(progressType);
31
- if (
32
- state &&
33
- (state.lastProgress === normalizedProgress || now - state.lastEmittedAt < intervalMs)
34
- ) {
35
- return false;
36
- }
37
-
38
- stateByType.set(progressType, {
39
- lastEmittedAt: now,
40
- lastProgress: normalizedProgress,
41
- });
42
- return true;
43
- };
44
- };