@ukeyfe/hardware-shared 1.1.13

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,751 @@
1
+ export interface IHardwareError {
2
+ errorCode: ValueOf<typeof HardwareErrorCode>;
3
+ message?: string;
4
+ params?: any;
5
+ }
6
+
7
+ type ValueOf<P extends object> = P[keyof P];
8
+
9
+ type HardwareErrorCodeMessageMapping = { [P in ValueOf<typeof HardwareErrorCode>]: string };
10
+
11
+ type ErrorCodeUnion = ValueOf<typeof HardwareErrorCode>;
12
+
13
+ function fillStringWithArguments(value: string, object: object) {
14
+ if (typeof value !== 'string') return value;
15
+ // Avoid regex with potential catastrophic backtracking by parsing manually in linear time
16
+ if (value.indexOf('{') === -1) return value;
17
+ let result = '';
18
+ let i = 0;
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ const dict = object as any;
21
+ while (i < value.length) {
22
+ const open = value.indexOf('{', i);
23
+ if (open === -1) {
24
+ result += value.slice(i);
25
+ break;
26
+ }
27
+ const close = value.indexOf('}', open + 1);
28
+ if (close === -1) {
29
+ // No matching closing brace; append the rest as-is
30
+ result += value.slice(i);
31
+ break;
32
+ }
33
+ // Append text before the placeholder
34
+ result += value.slice(i, open);
35
+ const key = value.slice(open + 1, close);
36
+ if (key.length === 0) {
37
+ // Keep '{}' unchanged to match original regex behavior
38
+ result += '{}';
39
+ } else {
40
+ const replacement = dict[key];
41
+ // Preserve original semantics: falsy values fallback to '?'
42
+ result += replacement ? String(replacement) : '?';
43
+ }
44
+ i = close + 1;
45
+ }
46
+ return result;
47
+ }
48
+
49
+ export class HardwareError extends Error {
50
+ errorCode: ErrorCodeUnion = HardwareErrorCode.UnknownError;
51
+
52
+ message = '';
53
+
54
+ params: any = {};
55
+
56
+ constructor(hardwareError: IHardwareError | string) {
57
+ super();
58
+ const errorMessageMapping = HardwareErrorCodeMessage;
59
+ this.message = errorMessageMapping[HardwareErrorCode.UnknownError];
60
+
61
+ if (typeof hardwareError === 'string') {
62
+ this.errorCode = HardwareErrorCode.UnknownError;
63
+ this.message = hardwareError;
64
+ } else {
65
+ const message = (hardwareError.message || errorMessageMapping[hardwareError.errorCode]) ?? '';
66
+ if (message) {
67
+ this.message = fillStringWithArguments(message, hardwareError);
68
+ }
69
+ this.params = hardwareError.params;
70
+ this.errorCode = hardwareError.errorCode;
71
+ }
72
+
73
+ this.name = 'HardwareError';
74
+ }
75
+ }
76
+
77
+ export const HardwareErrorCode = {
78
+ /**
79
+ * This error can be thrown when unexpected error occurred and in most cases it is related to implementation bug.
80
+ * Original message is available in message property.
81
+ */
82
+ UnknownError: 0,
83
+
84
+ /**
85
+ * Firmware version mismatch
86
+ */
87
+ DeviceFwException: 101,
88
+
89
+ /**
90
+ * Device unexpected mode
91
+ */
92
+ DeviceUnexpectedMode: 102,
93
+
94
+ /**
95
+ * Device list is not initialized
96
+ */
97
+ DeviceListNotInitialized: 103,
98
+
99
+ /**
100
+ * Please select the connected device
101
+ */
102
+ SelectDevice: 104,
103
+
104
+ /**
105
+ * Device not found
106
+ */
107
+ DeviceNotFound: 105,
108
+
109
+ /**
110
+ * Device is not initialized
111
+ */
112
+ DeviceInitializeFailed: 106,
113
+
114
+ /**
115
+ * Device interrupted from another operation
116
+ */
117
+ DeviceInterruptedFromOutside: 107,
118
+
119
+ /**
120
+ * Device should be in bootloader mode
121
+ */
122
+ RequiredButInBootloaderMode: 108,
123
+
124
+ /**
125
+ * Device interrupted from user
126
+ */
127
+ DeviceInterruptedFromUser: 109,
128
+
129
+ /**
130
+ * Check device id is same
131
+ */
132
+ DeviceCheckDeviceIdError: 110,
133
+
134
+ /**
135
+ * Do not support passphrase
136
+ * @params: { require: string }
137
+ */
138
+ DeviceNotSupportPassphrase: 111,
139
+
140
+ /*
141
+ * Device passphrase state error
142
+ */
143
+ DeviceCheckPassphraseStateError: 112,
144
+
145
+ /**
146
+ * use passphrase, but passphrase is not opened
147
+ */
148
+ DeviceNotOpenedPassphrase: 113,
149
+
150
+ /**
151
+ * not use passphrase, but passphrase is opened
152
+ */
153
+ DeviceOpenedPassphrase: 114,
154
+
155
+ /**
156
+ * Detect hardware that is in bootloader mode and return an error.
157
+ */
158
+ DeviceDetectInBootloaderMode: 115,
159
+
160
+ /**
161
+ * Device not allow in bootloader mode
162
+ */
163
+ NotAllowInBootloaderMode: 116,
164
+
165
+ /**
166
+ * Device is busy
167
+ */
168
+ DeviceBusy: 117,
169
+
170
+ /**
171
+ * Device check unlock type not match error
172
+ */
173
+ DeviceCheckUnlockTypeError: 118,
174
+
175
+ /**
176
+ * Not initialized
177
+ */
178
+ NotInitialized: 200,
179
+
180
+ /**
181
+ * Iframe not initialized
182
+ */
183
+ IFrameNotInitialized: 300,
184
+
185
+ /**
186
+ * iframe repeat initialization
187
+ */
188
+ IFrameAleradyInitialized: 301,
189
+
190
+ /**
191
+ * iframe load failure
192
+ */
193
+ IFrameLoadFail: 302,
194
+
195
+ /**
196
+ * init iframe time out
197
+ */
198
+ IframeTimeout: 303,
199
+
200
+ /**
201
+ * iframe blocked
202
+ */
203
+ IframeBlocked: 304,
204
+
205
+ /**
206
+ * iframe host not trust
207
+ */
208
+ IframeDistrust: 305,
209
+
210
+ /**
211
+ * Runtime errors during method execution
212
+ */
213
+ CallMethodError: 400,
214
+
215
+ /**
216
+ * Method does not responding
217
+ */
218
+ CallMethodNotResponse: 404,
219
+
220
+ /**
221
+ * Call method invalid parameter
222
+ */
223
+ CallMethodInvalidParameter: 405,
224
+
225
+ /**
226
+ * firmware update download failed
227
+ */
228
+ FirmwareUpdateDownloadFailed: 406,
229
+
230
+ /**
231
+ * Call method not supported, need update firmware
232
+ * @params: { current: string, require: string }
233
+ */
234
+ CallMethodNeedUpgradeFirmware: 407,
235
+
236
+ /**
237
+ * Call method not supported, is deprecated
238
+ * @params: { current: string, deprecated: string }
239
+ */
240
+ CallMethodDeprecated: 408,
241
+
242
+ /**
243
+ * Only one device can be connected during firmware upgrade
244
+ */
245
+ FirmwareUpdateLimitOneDevice: 409,
246
+
247
+ /**
248
+ * You need to manually enter boot
249
+ */
250
+ FirmwareUpdateManuallyEnterBoot: 410,
251
+
252
+ /**
253
+ * Manual entry fails. You must manually enter the boot
254
+ */
255
+ FirmwareUpdateAutoEnterBootFailure: 411,
256
+
257
+ /**
258
+ * The new firmware has not been released yet
259
+ */
260
+ NewFirmwareUnRelease: 412,
261
+
262
+ /**
263
+ * use UKey desktop client to update the firmware
264
+ * because need copy resource file to Touch
265
+ */
266
+ UseDesktopToUpdateFirmware: 413,
267
+
268
+ /**
269
+ * Mandatory firmware update
270
+ * @params:{ connectId: string? , deviceId: string? }
271
+ */
272
+ NewFirmwareForceUpdate: 414,
273
+
274
+ /**
275
+ * Device not support this method
276
+ */
277
+ DeviceNotSupportMethod: 415,
278
+
279
+ /**
280
+ * Forbidden key path
281
+ */
282
+ ForbiddenKeyPath: 416,
283
+
284
+ /**
285
+ * Repeat unlocking
286
+ * all network get address by loop need repeat unlocking
287
+ */
288
+ RepeatUnlocking: 417,
289
+
290
+ /**
291
+ * Defective firmware detected
292
+ */
293
+ DefectiveFirmware: 418,
294
+
295
+ /**
296
+ * Netword request error
297
+ */
298
+ NetworkError: 500,
299
+
300
+ /**
301
+ * Transport not configured
302
+ */
303
+ TransportNotConfigured: 600,
304
+
305
+ /**
306
+ * Transport call in progress
307
+ */
308
+ TransportCallInProgress: 601,
309
+
310
+ /**
311
+ * Transport not found
312
+ */
313
+ TransportNotFound: 602,
314
+
315
+ /**
316
+ * Transport invalid protobuf
317
+ */
318
+ TransportInvalidProtobuf: 603,
319
+
320
+ /**
321
+ * Bluetooth error code
322
+ */
323
+ BleScanError: 700,
324
+ BlePermissionError: 701,
325
+ BleLocationError: 702,
326
+ BleRequiredUUID: 703,
327
+ BleConnectedError: 704,
328
+ BleDeviceNotBonded: 705,
329
+ BleServiceNotFound: 706,
330
+ BleCharacteristicNotFound: 707,
331
+ BleMonitorError: 708,
332
+ BleCharacteristicNotifyError: 709,
333
+ BleWriteCharacteristicError: 710,
334
+ BleAlreadyConnected: 711,
335
+ BleLocationServicesDisabled: 712,
336
+ BleTimeoutError: 713,
337
+ BleForceCleanRunPromise: 714,
338
+ BleDeviceBondError: 715,
339
+ BleCharacteristicNotifyChangeFailure: 716,
340
+ BleTransportCallCanceled: 717,
341
+ BleDeviceBondedCanceled: 718,
342
+ BlePeerRemovedPairingInformation: 719,
343
+ BleDeviceDisconnected: 720,
344
+ BlePoweredOff: 721,
345
+ BleUnsupported: 722,
346
+
347
+ /**
348
+ * Hardware runtiome errors
349
+ */
350
+ RuntimeError: 800,
351
+
352
+ /**
353
+ * invalid pin
354
+ */
355
+ PinInvalid: 801,
356
+
357
+ /**
358
+ * pin cancelled by user
359
+ */
360
+ PinCancelled: 802,
361
+
362
+ /**
363
+ * Action cancelled by user
364
+ */
365
+ ActionCancelled: 803,
366
+
367
+ /**
368
+ * Firmware installation failed
369
+ */
370
+ FirmwareError: 804,
371
+
372
+ /**
373
+ * transport response unexpect error
374
+ */
375
+ ResponseUnexpectTypeError: 805,
376
+
377
+ /**
378
+ * bridge network error
379
+ */
380
+ BridgeNetworkError: 806,
381
+
382
+ /**
383
+ * Bridge network timeout
384
+ */
385
+ BridgeTimeoutError: 807,
386
+
387
+ /**
388
+ * Bridge not installed
389
+ */
390
+ BridgeNotInstalled: 808,
391
+
392
+ /**
393
+ * ensure connect timeout
394
+ */
395
+ PollingTimeout: 809,
396
+
397
+ /**
398
+ * ensure connect stop polling
399
+ */
400
+ PollingStop: 810,
401
+
402
+ /**
403
+ * Device does not open blid sign
404
+ */
405
+ BlindSignDisabled: 811,
406
+
407
+ UnexpectPassphrase: 812,
408
+
409
+ /**
410
+ * NFT file already exists
411
+ */
412
+ FileAlreadyExists: 813,
413
+
414
+ /**
415
+ * check file length error
416
+ */
417
+ CheckDownloadFileError: 814,
418
+
419
+ /**
420
+ * not in signing mode
421
+ */
422
+ NotInSigningMode: 815,
423
+
424
+ /**
425
+ * not in signing mode
426
+ */
427
+ DataOverload: 816,
428
+
429
+ /**
430
+ * device disconnected during action
431
+ */
432
+ BridgeDeviceDisconnected: 817,
433
+
434
+ /**
435
+ * BTC PSBT too many utxos
436
+ * @params:{ count: number }
437
+ */
438
+ BTCPsbtTooManyUtxos: 818,
439
+
440
+ /**
441
+ * EMMC file write firmware error
442
+ */
443
+ EmmcFileWriteFirmwareError: 819,
444
+
445
+ /**
446
+ * Firmware verification failed (e.g., bootloader file verify failed)
447
+ */
448
+ FirmwareVerificationFailed: 820,
449
+
450
+ /**
451
+ * Web bridge coonect needs permission
452
+ */
453
+ BridgeNeedsPermission: 821,
454
+
455
+ /**
456
+ * Lowlevel transport connect error
457
+ */
458
+ LowlevelTrasnportConnectError: 900,
459
+
460
+ /**
461
+ * Web USB or Web Bluetooth device not found or needs permission
462
+ */
463
+ WebDeviceNotFoundOrNeedsPermission: 901,
464
+
465
+ /**
466
+ * Web USB or Web Bluetooth device prompt access error
467
+ */
468
+ WebDevicePromptAccessError: 902,
469
+ } as const;
470
+
471
+ export const HardwareErrorCodeMessage: HardwareErrorCodeMessageMapping = {
472
+ [HardwareErrorCode.UnknownError]: 'Unknown error occurred. Check message property.',
473
+
474
+ /**
475
+ * Device Errors
476
+ */
477
+ [HardwareErrorCode.DeviceFwException]: 'Firmware version mismatch',
478
+ [HardwareErrorCode.DeviceUnexpectedMode]: 'Device unexpected mode',
479
+ [HardwareErrorCode.DeviceListNotInitialized]: 'Device list is not initialized',
480
+ [HardwareErrorCode.SelectDevice]: 'Please select the connected device',
481
+ [HardwareErrorCode.DeviceNotFound]: 'Device not found',
482
+ [HardwareErrorCode.DeviceInitializeFailed]: 'Device initialization failed',
483
+ [HardwareErrorCode.DeviceInterruptedFromOutside]: 'Device interrupted',
484
+ [HardwareErrorCode.DeviceInterruptedFromUser]: 'Device interrupted',
485
+ [HardwareErrorCode.RequiredButInBootloaderMode]: 'Device should be in bootloader mode',
486
+ [HardwareErrorCode.DeviceCheckDeviceIdError]: 'Device Id in the features is not same.',
487
+ [HardwareErrorCode.DeviceNotSupportPassphrase]: 'Device not support passphrase',
488
+ [HardwareErrorCode.DeviceCheckPassphraseStateError]: 'Device passphrase state error',
489
+ [HardwareErrorCode.DeviceNotOpenedPassphrase]: 'Device not opened passphrase',
490
+ [HardwareErrorCode.DeviceOpenedPassphrase]: 'Device opened passphrase',
491
+ [HardwareErrorCode.DeviceDetectInBootloaderMode]: 'Device in bootloader mode',
492
+ [HardwareErrorCode.NotAllowInBootloaderMode]: 'Device not allow in bootloader mode',
493
+ [HardwareErrorCode.DeviceBusy]: 'Device is busy',
494
+ [HardwareErrorCode.DeviceCheckUnlockTypeError]: 'Device check unlock type not match error',
495
+ /**
496
+ * Node Errors
497
+ */
498
+ [HardwareErrorCode.NotInitialized]: 'Not initialized',
499
+ /**
500
+ * Iframe Errors
501
+ */
502
+ [HardwareErrorCode.IFrameNotInitialized]: 'IFrame not initialized',
503
+ [HardwareErrorCode.IFrameAleradyInitialized]: 'IFrame alerady initialized',
504
+ [HardwareErrorCode.IFrameLoadFail]: 'IFrame load fail',
505
+ [HardwareErrorCode.IframeTimeout]: 'init iframe time out',
506
+ [HardwareErrorCode.IframeBlocked]: 'IFrame blocked',
507
+ [HardwareErrorCode.IframeDistrust]: 'IFrame host not trust',
508
+
509
+ /**
510
+ * Method Errors
511
+ */
512
+ [HardwareErrorCode.CallMethodError]: 'Runtime errors during method execution',
513
+ [HardwareErrorCode.CallMethodNotResponse]: 'Method does not responding',
514
+ [HardwareErrorCode.CallMethodInvalidParameter]: 'Call method invalid parameter',
515
+ [HardwareErrorCode.FirmwareUpdateDownloadFailed]: 'Firmware update download failed',
516
+ [HardwareErrorCode.CallMethodNeedUpgradeFirmware]: 'Call method need upgrade firmware',
517
+ [HardwareErrorCode.CallMethodDeprecated]: 'Call method is deprecated',
518
+ [HardwareErrorCode.FirmwareUpdateLimitOneDevice]:
519
+ 'Only one device can be connected during firmware upgrade',
520
+ [HardwareErrorCode.FirmwareUpdateManuallyEnterBoot]: 'You need to manually enter boot',
521
+ [HardwareErrorCode.FirmwareUpdateAutoEnterBootFailure]:
522
+ 'Description Failed to automatically enter boot',
523
+ [HardwareErrorCode.NewFirmwareUnRelease]: 'new firmware has not been released yet',
524
+ [HardwareErrorCode.NewFirmwareForceUpdate]: 'new firmware has been released, please update',
525
+ [HardwareErrorCode.UseDesktopToUpdateFirmware]:
526
+ 'Please use UKey desktop client to update the firmware',
527
+ [HardwareErrorCode.DeviceNotSupportMethod]: 'Device not support this method',
528
+ [HardwareErrorCode.ForbiddenKeyPath]: 'Forbidden key path',
529
+ [HardwareErrorCode.RepeatUnlocking]: 'Repeat unlocking',
530
+ [HardwareErrorCode.DefectiveFirmware]: 'Device firmware is defective, please update immediately',
531
+
532
+ /**
533
+ * Network Errors
534
+ */
535
+ [HardwareErrorCode.NetworkError]: 'Network request error',
536
+
537
+ /**
538
+ * Transport Errors
539
+ */
540
+ [HardwareErrorCode.TransportNotConfigured]: 'Transport not configured',
541
+ [HardwareErrorCode.TransportCallInProgress]: 'Transport call in progress',
542
+ [HardwareErrorCode.TransportNotFound]: 'Transport not found',
543
+ [HardwareErrorCode.TransportInvalidProtobuf]: 'Transport invalid protobuf',
544
+
545
+ /**
546
+ * Bluetooth Error
547
+ */
548
+ [HardwareErrorCode.BleScanError]: 'BLE scan error',
549
+ [HardwareErrorCode.BlePermissionError]: 'Bluetooth required to be turned on',
550
+ [HardwareErrorCode.BleLocationError]:
551
+ 'Location permissions for the application are not available',
552
+ [HardwareErrorCode.BleRequiredUUID]: 'uuid is required',
553
+ [HardwareErrorCode.BleConnectedError]: 'connected error is always runtime error',
554
+ [HardwareErrorCode.BleDeviceNotBonded]: 'device is not bonded',
555
+ [HardwareErrorCode.BleDeviceBondedCanceled]: 'device is canceled bonding',
556
+ [HardwareErrorCode.BlePeerRemovedPairingInformation]: 'need to delete pairing information',
557
+ [HardwareErrorCode.BleServiceNotFound]: 'BLEServiceNotFound: service not found',
558
+ [HardwareErrorCode.BleCharacteristicNotFound]: 'BLEServiceNotFound: service not found',
559
+ [HardwareErrorCode.BleMonitorError]: 'Monitor Error: characteristic not found',
560
+ [HardwareErrorCode.BleCharacteristicNotifyError]: 'Characteristic Notify Error',
561
+ [HardwareErrorCode.BleWriteCharacteristicError]: 'Write Characteristic Error',
562
+ [HardwareErrorCode.BleAlreadyConnected]: 'Already connected to device',
563
+ [HardwareErrorCode.BleLocationServicesDisabled]: 'Location Services disabled',
564
+ [HardwareErrorCode.BleTimeoutError]: 'The connection has timed out unexpectedly.',
565
+ [HardwareErrorCode.BleForceCleanRunPromise]: 'Force clean Bluetooth run promise',
566
+ [HardwareErrorCode.BleDeviceBondError]: 'Bluetooth pairing failed',
567
+ [HardwareErrorCode.BleCharacteristicNotifyChangeFailure]: 'Characteristic Notify Change Failure',
568
+ [HardwareErrorCode.BleTransportCallCanceled]: 'Ble Transport call canceled',
569
+ [HardwareErrorCode.BleDeviceDisconnected]: 'Device disconnected',
570
+ [HardwareErrorCode.BlePoweredOff]: 'Bluetooth is turned off',
571
+ [HardwareErrorCode.BleUnsupported]: 'Bluetooth is not supported on this device',
572
+
573
+ /**
574
+ * Runtime Error
575
+ */
576
+ [HardwareErrorCode.RuntimeError]: 'Runtime error',
577
+ [HardwareErrorCode.PinInvalid]: 'Pin invalid',
578
+ [HardwareErrorCode.PinCancelled]: 'Pin cancelled',
579
+ [HardwareErrorCode.ActionCancelled]: 'Action cancelled by user',
580
+ [HardwareErrorCode.FirmwareError]: 'Firmware installation failed',
581
+ [HardwareErrorCode.ResponseUnexpectTypeError]: 'Response type is not expected',
582
+ [HardwareErrorCode.BridgeNetworkError]: 'Bridge network error',
583
+ [HardwareErrorCode.BridgeTimeoutError]: 'Bridge network timeout',
584
+ [HardwareErrorCode.BridgeNotInstalled]: 'Bridge not installed',
585
+ [HardwareErrorCode.BridgeDeviceDisconnected]: 'Bridge device disconnected during action',
586
+ [HardwareErrorCode.PollingTimeout]: 'Polling timeout',
587
+ [HardwareErrorCode.PollingStop]: 'Polling stop',
588
+ [HardwareErrorCode.BlindSignDisabled]: 'Please confirm the BlindSign enabled',
589
+ [HardwareErrorCode.UnexpectPassphrase]: 'Unexpect passphrase',
590
+ [HardwareErrorCode.FileAlreadyExists]: 'File already exists',
591
+ [HardwareErrorCode.CheckDownloadFileError]: 'Check download file error',
592
+ [HardwareErrorCode.NotInSigningMode]: 'not in signing mode',
593
+ [HardwareErrorCode.DataOverload]: 'Params data overload',
594
+ [HardwareErrorCode.BTCPsbtTooManyUtxos]: 'PSBT too many utxos',
595
+ [HardwareErrorCode.EmmcFileWriteFirmwareError]: 'EMMC file write firmware error',
596
+ [HardwareErrorCode.FirmwareVerificationFailed]: 'Firmware verification failed',
597
+ [HardwareErrorCode.BridgeNeedsPermission]: 'Bridge needs permission',
598
+
599
+ /**
600
+ * Lowlevel transport
601
+ */
602
+ [HardwareErrorCode.LowlevelTrasnportConnectError]: 'Lowlevel transport connect error',
603
+ [HardwareErrorCode.WebDeviceNotFoundOrNeedsPermission]:
604
+ 'Web-USB or Web-Bluetooth device not found or needs permission',
605
+ [HardwareErrorCode.WebDevicePromptAccessError]:
606
+ 'Web-USB or Web-Bluetooth device prompt access error',
607
+ } as const;
608
+
609
+ export const TypedError = (
610
+ hardwareError: ErrorCodeUnion | string,
611
+ message?: string,
612
+ params?: any
613
+ ) => {
614
+ if (typeof hardwareError === 'string') {
615
+ return new HardwareError(hardwareError);
616
+ }
617
+ return new HardwareError({ errorCode: hardwareError, message: message ?? '', params });
618
+ };
619
+
620
+ export const serializeError = (payload: any) => {
621
+ if (payload && payload.error instanceof HardwareError) {
622
+ return {
623
+ error: payload.error.message,
624
+ code: payload.error.errorCode,
625
+ params: payload.error.params,
626
+ };
627
+ }
628
+ if (payload && payload.error && payload.error.name === 'AxiosError') {
629
+ return { error: payload.error.message, code: HardwareErrorCode.BridgeNetworkError };
630
+ }
631
+ if (payload && payload.error instanceof Error) {
632
+ return { error: payload.error.message, code: payload.error.code };
633
+ }
634
+ return payload;
635
+ };
636
+
637
+ export const CreateErrorByMessage = (message: string): HardwareError => {
638
+ for (const code of Object.values(HardwareErrorCode)) {
639
+ if (HardwareErrorCodeMessage[code] === message) {
640
+ return TypedError(code);
641
+ }
642
+ }
643
+ return new HardwareError(message);
644
+ };
645
+
646
+ // Map low-level bridge/libusb error strings to structured HardwareError
647
+ export const CreateHardwareErrorByBridgeError = (raw: string): HardwareError => {
648
+ const msg = String(raw || '');
649
+ // Permission denied when accessing USB device via libusb (e.g., missing udev rules)
650
+ if (msg.includes('LIBUSB_ERROR_ACCESS')) {
651
+ return TypedError(HardwareErrorCode.BridgeNeedsPermission, 'LIBUSB_ERROR_ACCESS');
652
+ }
653
+ // Fallback: treat as bridge/network error with original message
654
+ return TypedError(HardwareErrorCode.BridgeNetworkError, msg);
655
+ };
656
+
657
+ const createNewFirmwareUnReleaseHardwareError = (
658
+ currentVersion: string,
659
+ requireVersion: string,
660
+ methodName?: string
661
+ ) => {
662
+ const methodInfo = methodName ? ` for method '${methodName}'` : '';
663
+ return TypedError(
664
+ HardwareErrorCode.NewFirmwareUnRelease,
665
+ `Device firmware version is too low${methodInfo}, please update to the latest version`,
666
+ { current: currentVersion, require: requireVersion, method: methodName }
667
+ );
668
+ };
669
+
670
+ const createNeedUpgradeFirmwareHardwareError = (
671
+ currentVersion: string,
672
+ requireVersion: string,
673
+ methodName?: string
674
+ ) => {
675
+ const methodInfo = methodName ? ` for method '${methodName}'` : '';
676
+ return TypedError(
677
+ HardwareErrorCode.CallMethodNeedUpgradeFirmware,
678
+ `Device firmware version is too low${methodInfo}, please update to ${requireVersion}`,
679
+ { current: currentVersion, require: requireVersion, method: methodName }
680
+ );
681
+ };
682
+
683
+ const createNewFirmwareForceUpdateHardwareError = (
684
+ connectId: string | undefined,
685
+ deviceId: string | undefined,
686
+ versionTypes?: ('firmware' | 'ble')[],
687
+ currentVersions?: {
688
+ firmware?: string;
689
+ ble?: string;
690
+ }
691
+ ) => {
692
+ const types = versionTypes || [];
693
+ const typeMap = { firmware: 'firmware', ble: 'BLE firmware' };
694
+ const requiredTypes = types.filter(type => type in typeMap);
695
+
696
+ const getVersionInfo = () => {
697
+ const versions = [];
698
+ if (currentVersions?.firmware) versions.push(`firmware version: ${currentVersions.firmware}`);
699
+ if (currentVersions?.ble) versions.push(`BLE version: ${currentVersions.ble}`);
700
+ return versions.length > 0 ? ` (${versions.join(', ')})` : '';
701
+ };
702
+
703
+ const getTypeDescription = () => requiredTypes.map(type => typeMap[type]).join(' and ');
704
+ const message = `Device ${getTypeDescription()} version is too low. ${getVersionInfo()}`;
705
+
706
+ return TypedError(HardwareErrorCode.NewFirmwareForceUpdate, message, {
707
+ connectId,
708
+ deviceId,
709
+ versionTypes,
710
+ currentVersions,
711
+ });
712
+ };
713
+
714
+ const createDeprecatedHardwareError = (
715
+ currentVersion: string,
716
+ deprecatedVersion: string,
717
+ methodName?: string
718
+ ) => {
719
+ const methodInfo = methodName ? ` Method '${methodName}'` : 'This method';
720
+ return TypedError(
721
+ HardwareErrorCode.CallMethodDeprecated,
722
+ `Device firmware version is too high. ${methodInfo} has been deprecated in ${deprecatedVersion}`,
723
+ { current: currentVersion, deprecated: deprecatedVersion, method: methodName }
724
+ );
725
+ };
726
+
727
+ const createDefectiveFirmwareError = (
728
+ serialNo: string,
729
+ seVersion: string,
730
+ deviceType: string,
731
+ connectId?: string,
732
+ deviceId?: string
733
+ ) => {
734
+ const message = `Defective firmware detected (Serial: ${serialNo}, SE: ${seVersion}). Please update immediately.`;
735
+
736
+ return TypedError(HardwareErrorCode.DefectiveFirmware, message, {
737
+ serialNo,
738
+ seVersion,
739
+ deviceType,
740
+ connectId,
741
+ deviceId,
742
+ });
743
+ };
744
+
745
+ export {
746
+ createNewFirmwareUnReleaseHardwareError,
747
+ createNeedUpgradeFirmwareHardwareError,
748
+ createNewFirmwareForceUpdateHardwareError,
749
+ createDeprecatedHardwareError,
750
+ createDefectiveFirmwareError,
751
+ };