id-scanner-lib 1.3.3 → 1.6.2

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 (80) hide show
  1. package/README.md +324 -410
  2. package/dist/id-scanner-lib.esm.js +4826 -0
  3. package/dist/id-scanner-lib.esm.js.map +1 -0
  4. package/dist/id-scanner-lib.js +4858 -0
  5. package/dist/id-scanner-lib.js.map +1 -0
  6. package/dist/types/browser-image-compression.d.ts +19 -0
  7. package/dist/types/tesseract.d.ts +280 -0
  8. package/package.json +89 -78
  9. package/src/core/base-module.ts +78 -0
  10. package/src/core/camera-manager.ts +813 -0
  11. package/src/core/config.ts +305 -0
  12. package/src/core/errors.ts +174 -0
  13. package/src/core/event-emitter.test.ts +42 -0
  14. package/src/core/event-emitter.ts +110 -0
  15. package/src/core/loading-state.test.ts +67 -0
  16. package/src/core/loading-state.ts +156 -0
  17. package/src/core/logger.test.ts +49 -0
  18. package/src/core/logger.ts +549 -0
  19. package/src/core/module-manager.ts +163 -0
  20. package/src/core/plugin-manager.ts +429 -0
  21. package/src/core/resource-manager.ts +762 -0
  22. package/src/core/result.ts +163 -0
  23. package/src/core/scanner-factory.ts +236 -0
  24. package/src/index.ts +117 -939
  25. package/src/interfaces/external-types.ts +200 -0
  26. package/src/interfaces/face-detection.ts +309 -0
  27. package/src/interfaces/scanner-module.ts +384 -0
  28. package/src/modules/face/face-detector.ts +988 -0
  29. package/src/modules/face/index.ts +208 -0
  30. package/src/modules/face/liveness-detector.ts +908 -0
  31. package/src/modules/face/types.ts +133 -0
  32. package/src/{id-recognition → modules/id-card}/anti-fake-detector.ts +274 -240
  33. package/src/modules/id-card/id-card-detector.ts +474 -0
  34. package/src/modules/id-card/index.ts +425 -0
  35. package/src/{id-recognition → modules/id-card}/ocr-processor.ts +149 -92
  36. package/src/modules/id-card/ocr-worker.ts +259 -0
  37. package/src/modules/id-card/types.ts +178 -0
  38. package/src/modules/qrcode/index.ts +175 -0
  39. package/src/modules/qrcode/qr-code-scanner.ts +231 -0
  40. package/src/modules/qrcode/types.ts +169 -0
  41. package/src/types/common.test.ts +99 -0
  42. package/src/types/common.ts +166 -0
  43. package/src/types/tesseract.d.ts +265 -22
  44. package/src/utils/camera.test.ts +30 -0
  45. package/src/utils/camera.ts +4 -1
  46. package/src/utils/error-handler.test.ts +137 -0
  47. package/src/utils/error-handler.ts +110 -0
  48. package/src/utils/image-processing.ts +68 -49
  49. package/src/utils/index.test.ts +186 -0
  50. package/src/utils/index.ts +429 -0
  51. package/src/utils/performance.ts +168 -131
  52. package/src/utils/resource-manager.ts +65 -146
  53. package/src/utils/retry.test.ts +142 -0
  54. package/src/utils/retry.ts +282 -0
  55. package/src/utils/types.ts +90 -2
  56. package/src/utils/utils.test.ts +171 -0
  57. package/src/utils/worker.ts +123 -84
  58. package/src/version.ts +11 -0
  59. package/tools/scaffold.js +543 -0
  60. package/dist/id-scanner-core.esm.js +0 -11349
  61. package/dist/id-scanner-core.js +0 -11361
  62. package/dist/id-scanner-core.min.js +0 -1
  63. package/dist/id-scanner-ocr.esm.js +0 -2319
  64. package/dist/id-scanner-ocr.js +0 -2328
  65. package/dist/id-scanner-ocr.min.js +0 -1
  66. package/dist/id-scanner-qr.esm.js +0 -1296
  67. package/dist/id-scanner-qr.js +0 -1305
  68. package/dist/id-scanner-qr.min.js +0 -1
  69. package/dist/id-scanner.js +0 -4561
  70. package/dist/id-scanner.min.js +0 -1
  71. package/src/core.ts +0 -138
  72. package/src/demo/demo.ts +0 -204
  73. package/src/id-recognition/data-extractor.ts +0 -262
  74. package/src/id-recognition/id-detector.ts +0 -510
  75. package/src/id-recognition/ocr-worker.ts +0 -156
  76. package/src/index-umd.ts +0 -477
  77. package/src/ocr-module.ts +0 -187
  78. package/src/qr-module.ts +0 -179
  79. package/src/scanner/barcode-scanner.ts +0 -251
  80. package/src/scanner/qr-scanner.ts +0 -167
@@ -2,36 +2,279 @@
2
2
  * Type definitions for tesseract.js
3
3
  */
4
4
 
5
- declare module 'tesseract.js' {
5
+ declare module "tesseract.js" {
6
+ // Based on https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts
7
+ // and https://github.com/naptha/tesseract.js/blob/master/docs/api.md
8
+
9
+ export interface Point {
10
+ x: number
11
+ y: number
12
+ }
13
+
14
+ export interface Bbox {
15
+ x0: number
16
+ y0: number
17
+ x1: number
18
+ y1: number
19
+ }
20
+
21
+ export interface Baseline {
22
+ x0: number
23
+ y0: number
24
+ x1: number
25
+ y1: number
26
+ has_descenders: boolean
27
+ has_ascenders: boolean
28
+ }
29
+
30
+ export interface Word {
31
+ symbols: Symbol[]
32
+ choices: Choice[]
33
+ text: string
34
+ confidence: number
35
+ baseline: Baseline
36
+ bbox: Bbox
37
+ is_numeric: boolean
38
+ in_dictionary: boolean
39
+ direction: string
40
+ language: string
41
+ is_from_dictionary: boolean
42
+ is_fuzzy: boolean
43
+ is_certain: boolean
44
+ is_bold: boolean
45
+ is_italic: boolean
46
+ is_underlined: boolean
47
+ is_monospace: boolean
48
+ is_serif: boolean
49
+ is_smallcaps: boolean
50
+ font_id: number
51
+ font_size: number
52
+ font_name: string
53
+ }
54
+
55
+ export interface Symbol {
56
+ choices: Choice[]
57
+ image: null | HTMLImageElement // Or string if it's a path/URL
58
+ text: string
59
+ confidence: number
60
+ baseline: Baseline
61
+ bbox: Bbox
62
+ is_superscript: boolean
63
+ is_subscript: boolean
64
+ is_dropcap: boolean
65
+ }
66
+
67
+ export interface Choice {
68
+ text: string
69
+ confidence: number
70
+ }
71
+
72
+ export interface Line {
73
+ words: Word[]
74
+ text: string
75
+ confidence: number
76
+ baseline: Baseline
77
+ bbox: Bbox
78
+ }
79
+
80
+ export interface Paragraph {
81
+ lines: Line[]
82
+ text: string
83
+ confidence: number
84
+ baseline: Baseline
85
+ bbox: Bbox
86
+ is_ltr: boolean
87
+ }
88
+
89
+ export interface Block {
90
+ paragraphs: Paragraph[]
91
+ lines: Line[]
92
+ words: Word[]
93
+ text: string
94
+ confidence: number
95
+ baseline: Baseline
96
+ bbox: Bbox
97
+ blocktype: string
98
+ polygon: Point[]
99
+ }
100
+
101
+ export interface Page {
102
+ blocks: Block[]
103
+ confidence: number
104
+ html: string // HTML representation of the page
105
+ jobId?: string
106
+ text: string
107
+ lines: Line[]
108
+ oem: string
109
+ operator: string
110
+ paragraphs: Paragraph[]
111
+ psm: string
112
+ symbols: Symbol[]
113
+ version: string
114
+ words: Word[]
115
+ hocr?: string // hOCR output
116
+ tsv?: string // TSV output
117
+ }
118
+
119
+ export interface LoggerMessage {
120
+ jobId?: string
121
+ workerId?: string
122
+ status: string
123
+ progress: number
124
+ userfriendlyText?: string
125
+ }
126
+
6
127
  export interface WorkerOptions {
7
- langPath?: string;
8
- corePath?: string;
9
- workerPath?: string;
10
- logger?: (message: any) => void;
11
- errorHandler?: (error: Error) => void;
128
+ langPath?: string
129
+ corePath?: string
130
+ workerPath?: string
131
+ logger?: (message: LoggerMessage) => void // More specific type for logger message <mcreference index="1" link="https://github.com/naptha/tesseract.js/blob/master/docs/api.md"></mcreference>
132
+ errorHandler?: (error: Error) => void
133
+ // Add other options based on documentation if needed
134
+ [key: string]: any // For other less common or dynamic options
12
135
  }
13
136
 
14
137
  export interface RecognizeResult {
138
+ data: Page // Use the detailed Page interface
139
+ }
140
+
141
+ export interface DetectResult {
15
142
  data: {
16
- text: string;
17
- hocr: string;
18
- tsv: string;
19
- confidence: number;
20
- blocks: any[];
21
- lines: any[];
22
- words: any[];
23
- symbols: any[];
24
- };
143
+ tesseract_script_id: number | null
144
+ script: string | null
145
+ script_confidence: number | null
146
+ orientation_degrees: number | null
147
+ orientation_confidence: number | null
148
+ }
149
+ jobId?: string
150
+ }
151
+
152
+ export interface ConfigResult {
153
+ data: null
154
+ jobId?: string
25
155
  }
26
156
 
157
+ export type ImageLike =
158
+ | HTMLImageElement
159
+ | HTMLCanvasElement
160
+ | File
161
+ | string
162
+ | Buffer
163
+ | ImageData // Common image types
164
+
27
165
  export interface Worker {
28
- load(): Promise<any>;
29
- loadLanguage(lang: string): Promise<any>;
30
- initialize(lang: string): Promise<any>;
31
- setParameters(params: Record<string, any>): Promise<any>;
32
- recognize(image: HTMLCanvasElement | ImageData | Buffer | string): Promise<RecognizeResult>;
33
- terminate(): Promise<any>;
166
+ load(jobId?: string): Promise<ConfigResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
167
+ loadLanguage(
168
+ langs?: string | string[],
169
+ jobId?: string
170
+ ): Promise<ConfigResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
171
+ initialize(
172
+ langs?: string | string[],
173
+ oem?: OEM,
174
+ config?: string | Partial<InitOptions>,
175
+ jobId?: string
176
+ ): Promise<ConfigResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
177
+ setParameters(
178
+ params: Partial<Parameters>,
179
+ jobId?: string
180
+ ): Promise<ConfigResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
181
+ recognize(
182
+ image: ImageLike,
183
+ options?: Partial<RecognizeOptions>,
184
+ output?: Partial<OutputFormats>,
185
+ jobId?: string
186
+ ): Promise<RecognizeResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
187
+ detect(
188
+ image: ImageLike,
189
+ options?: Partial<WorkerOptions>,
190
+ jobId?: string
191
+ ): Promise<DetectResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
192
+ terminate(jobId?: string): Promise<ConfigResult> // <mcreference index="4" link="https://github.com/naptha/tesseract.js/blob/master/src/index.d.ts"></mcreference>
193
+ // Add other worker methods if present in the version you are targeting
194
+ // Example from docs for other methods like FS operations:
195
+ writeText?(
196
+ path: string,
197
+ text: string,
198
+ jobId?: string
199
+ ): Promise<ConfigResult>
200
+ readText?(path: string, jobId?: string): Promise<ConfigResult>
201
+ removeFile?(path: string, jobId?: string): Promise<ConfigResult> // Assuming removeFile also returns ConfigResult or similar
202
+ FS?(method: string, args: any[], jobId?: string): Promise<any> // FS is more generic
203
+ }
204
+
205
+ // Based on Tesseract's OEM and PSM enums
206
+ export enum OEM {
207
+ TESSERACT_ONLY = 0,
208
+ LSTM_ONLY = 1,
209
+ TESSERACT_LSTM_COMBINED = 2,
210
+ DEFAULT = 3,
211
+ }
212
+
213
+ export enum PSM {
214
+ OSD_ONLY = 0,
215
+ AUTO_OSD = 1,
216
+ AUTO_ONLY = 2,
217
+ AUTO = 3,
218
+ SINGLE_COLUMN = 4,
219
+ SINGLE_BLOCK_VERT_TEXT = 5,
220
+ SINGLE_BLOCK = 6,
221
+ SINGLE_LINE = 7,
222
+ SINGLE_WORD = 8,
223
+ CIRCLE_WORD = 9,
224
+ SINGLE_CHAR = 10,
225
+ SPARSE_TEXT = 11,
226
+ SPARSE_TEXT_OSD = 12,
227
+ RAW_LINE = 13,
228
+ }
229
+
230
+ export interface Parameters {
231
+ tessedit_char_whitelist?: string
232
+ tessedit_pageseg_mode?: PSM
233
+ // Add other Tesseract parameters as needed
234
+ [key: string]: any // For flexibility with other parameters
235
+ }
236
+
237
+ export interface RecognizeOptions {
238
+ rectangle?: Bbox // For recognizing a specific region
239
+ rectangles?: Bbox[] // For recognizing multiple regions
240
+ // Add other recognize specific options
241
+ [key: string]: any
34
242
  }
35
243
 
36
- export function createWorker(options?: WorkerOptions): Worker;
244
+ export interface OutputFormats {
245
+ text?: boolean
246
+ blocks?: boolean
247
+ hocr?: boolean
248
+ tsv?: boolean
249
+ pdf?: boolean // If PDF output is supported
250
+ // Add other output formats
251
+ [key: string]: any
252
+ }
253
+
254
+ export interface InitOptions {
255
+ load_system_dawg?: boolean
256
+ load_freq_dawg?: boolean
257
+ load_punc_dawg?: boolean
258
+ load_number_dawg?: boolean
259
+ load_unambig_dawg?: boolean
260
+ load_bigram_dawg?: boolean
261
+ load_fixed_length_dawgs?: boolean
262
+ // Add other init-only parameters
263
+ [key: string]: any
264
+ }
265
+
266
+ export function createWorker(options?: Partial<WorkerOptions>): Worker // 修正返回类型为 Worker 而非 Promise<Worker>
267
+ export function setLogging(logging: boolean): void
268
+ export function recognize(
269
+ image: ImageLike,
270
+ langs?: string | string[],
271
+ options?: Partial<RecognizeOptions & WorkerOptions>
272
+ ): Promise<RecognizeResult>
273
+ export function detect(
274
+ image: ImageLike,
275
+ options?: Partial<WorkerOptions>
276
+ ): Promise<DetectResult>
277
+
278
+ // 正确导出 OEM 和 PSM 枚举
279
+ export { OEM, PSM }
37
280
  }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @file 摄像头工具测试
3
+ * @description 测试摄像头相关工具
4
+ */
5
+
6
+ import { getMediaConstraints } from './index';
7
+
8
+ describe('Camera Utils', () => {
9
+ describe('getMediaConstraints', () => {
10
+ it('should return default constraints', () => {
11
+ const constraints = getMediaConstraints();
12
+
13
+ expect(constraints).toBeDefined();
14
+ expect(constraints.audio).toBe(false);
15
+ expect(constraints.video).toBeDefined();
16
+ });
17
+
18
+ it('should accept custom parameters', () => {
19
+ const constraints = getMediaConstraints(1920, 1080, 'user', 60);
20
+
21
+ expect(constraints.video).toBeDefined();
22
+ });
23
+
24
+ it('should handle partial parameters', () => {
25
+ const constraints = getMediaConstraints(640);
26
+
27
+ expect(constraints.video).toBeDefined();
28
+ });
29
+ });
30
+ });
@@ -4,6 +4,8 @@
4
4
  * @module Camera
5
5
  */
6
6
 
7
+ import { Logger } from '../core/logger';
8
+
7
9
  /**
8
10
  * 相机配置选项接口
9
11
  *
@@ -113,7 +115,8 @@ export class Camera {
113
115
  });
114
116
  }
115
117
  } catch (error) {
116
- console.error('无法访问摄像头:', error);
118
+ const logger = Logger.getInstance();
119
+ logger.error('Camera', '无法访问摄像头', error instanceof Error ? error : undefined);
117
120
  throw new Error('无法访问摄像头。请确保已授予摄像头访问权限,并且摄像头未被其他应用程序占用。');
118
121
  }
119
122
  }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * @file 错误处理工具测试
3
+ * @description 测试 ErrorHandler
4
+ */
5
+
6
+ import { ErrorHandler, ErrorSeverity } from './error-handler';
7
+
8
+ describe('ErrorHandler', () => {
9
+ // Mock Logger
10
+ const mockLogger = {
11
+ debug: jest.fn(),
12
+ info: jest.fn(),
13
+ warn: jest.fn(),
14
+ error: jest.fn()
15
+ };
16
+
17
+ beforeAll(() => {
18
+ // Replace logger with mock
19
+ (ErrorHandler as any).logger = mockLogger;
20
+ });
21
+
22
+ beforeEach(() => {
23
+ jest.clearAllMocks();
24
+ });
25
+
26
+ it('should handle error with ERROR severity', () => {
27
+ ErrorHandler.handle('TestModule', 'Test error', new Error('test error'));
28
+
29
+ expect(mockLogger.error).toHaveBeenCalledWith(
30
+ 'TestModule',
31
+ 'Test error',
32
+ expect.any(Error)
33
+ );
34
+ });
35
+
36
+ it('should handle error with WARN severity', () => {
37
+ ErrorHandler.handle('TestModule', 'Warning message', null, ErrorSeverity.WARN);
38
+
39
+ expect(mockLogger.warn).toHaveBeenCalledWith(
40
+ 'TestModule',
41
+ 'Warning message',
42
+ undefined
43
+ );
44
+ });
45
+
46
+ it('should handle error with INFO severity', () => {
47
+ ErrorHandler.handle('TestModule', 'Info message', null, ErrorSeverity.INFO);
48
+
49
+ expect(mockLogger.info).toHaveBeenCalledWith(
50
+ 'TestModule',
51
+ 'Info message',
52
+ undefined
53
+ );
54
+ });
55
+
56
+ it('should handle error with DEBUG severity', () => {
57
+ ErrorHandler.handle('TestModule', 'Debug message', null, ErrorSeverity.DEBUG);
58
+
59
+ expect(mockLogger.debug).toHaveBeenCalledWith(
60
+ 'TestModule',
61
+ 'Debug message',
62
+ undefined
63
+ );
64
+ });
65
+
66
+ it('should convert string error to Error object', () => {
67
+ ErrorHandler.handle('TestModule', 'Test error', 'string error');
68
+
69
+ expect(mockLogger.error).toHaveBeenCalledWith(
70
+ 'TestModule',
71
+ 'Test error',
72
+ expect.any(Error)
73
+ );
74
+ });
75
+
76
+ it('should convert unknown error to Error object', () => {
77
+ ErrorHandler.handle('TestModule', 'Test error', { code: 123 });
78
+
79
+ expect(mockLogger.error).toHaveBeenCalledWith(
80
+ 'TestModule',
81
+ 'Test error',
82
+ expect.any(Error)
83
+ );
84
+ });
85
+
86
+ describe('asyncHandler', () => {
87
+ it('should create error handler function', () => {
88
+ const handler = ErrorHandler.asyncHandler('TestModule', 'Operation failed');
89
+
90
+ handler(new Error('test'));
91
+
92
+ expect(mockLogger.error).toHaveBeenCalledWith(
93
+ 'TestModule',
94
+ 'Operation failed',
95
+ expect.any(Error)
96
+ );
97
+ });
98
+ });
99
+
100
+ describe('safeExecute', () => {
101
+ it('should return result on success', async () => {
102
+ const fn = async () => 'success';
103
+ const result = await ErrorHandler.safeExecute(fn, 'TestModule', 'fallback');
104
+
105
+ expect(result).toBe('success');
106
+ });
107
+
108
+ it('should return fallback on error', async () => {
109
+ const fn = async () => {
110
+ throw new Error('error');
111
+ };
112
+ const result = await ErrorHandler.safeExecute(fn, 'TestModule', 'fallback');
113
+
114
+ expect(result).toBe('fallback');
115
+ expect(mockLogger.error).toHaveBeenCalled();
116
+ });
117
+ });
118
+
119
+ describe('safeExecuteSync', () => {
120
+ it('should return result on success', () => {
121
+ const fn = () => 'success';
122
+ const result = ErrorHandler.safeExecuteSync(fn, 'TestModule', 'fallback');
123
+
124
+ expect(result).toBe('success');
125
+ });
126
+
127
+ it('should return fallback on error', () => {
128
+ const fn = () => {
129
+ throw new Error('error');
130
+ };
131
+ const result = ErrorHandler.safeExecuteSync(fn, 'TestModule', 'fallback');
132
+
133
+ expect(result).toBe('fallback');
134
+ expect(mockLogger.error).toHaveBeenCalled();
135
+ });
136
+ });
137
+ });
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @file 统一错误处理工具
3
+ * @description 提供统一的错误处理和日志记录功能
4
+ * @module utils/error-handler
5
+ */
6
+
7
+ import { Logger } from '../core/logger';
8
+
9
+ /**
10
+ * 错误严重级别
11
+ */
12
+ export enum ErrorSeverity {
13
+ DEBUG = 'debug',
14
+ INFO = 'info',
15
+ WARN = 'warn',
16
+ ERROR = 'error'
17
+ }
18
+
19
+ /**
20
+ * 错误处理工具类
21
+ */
22
+ export class ErrorHandler {
23
+ private static logger = Logger.getInstance();
24
+
25
+ /**
26
+ * 处理错误并记录日志
27
+ * @param context 错误上下文(模块名)
28
+ * @param message 错误消息
29
+ * @param error 错误对象
30
+ * @param severity 错误级别
31
+ */
32
+ static handle(
33
+ context: string,
34
+ message: string,
35
+ error?: unknown,
36
+ severity: ErrorSeverity = ErrorSeverity.ERROR
37
+ ): void {
38
+ const errorObj = error instanceof Error ? error : error ? new Error(String(error)) : undefined;
39
+
40
+ switch (severity) {
41
+ case ErrorSeverity.DEBUG:
42
+ this.logger.debug(context, message, errorObj);
43
+ break;
44
+ case ErrorSeverity.INFO:
45
+ this.logger.info(context, message, errorObj);
46
+ break;
47
+ case ErrorSeverity.WARN:
48
+ this.logger.warn(context, message, errorObj);
49
+ break;
50
+ case ErrorSeverity.ERROR:
51
+ default:
52
+ this.logger.error(context, message, errorObj);
53
+ }
54
+ }
55
+
56
+ /**
57
+ * 处理异步错误
58
+ * @param context 错误上下文
59
+ * @param message 错误消息
60
+ * @returns 返回一个错误处理函数
61
+ */
62
+ static asyncHandler(
63
+ context: string,
64
+ message: string
65
+ ): (error: unknown) => void {
66
+ return (error: unknown) => {
67
+ this.handle(context, message, error);
68
+ };
69
+ }
70
+
71
+ /**
72
+ * 安全执行异步函数并处理错误
73
+ * @param fn 异步函数
74
+ * @param context 错误上下文
75
+ * @param fallbackValue 错误时的返回值
76
+ * @returns 函数结果或 fallbackValue
77
+ */
78
+ static async safeExecute<T>(
79
+ fn: () => Promise<T>,
80
+ context: string,
81
+ fallbackValue: T
82
+ ): Promise<T> {
83
+ try {
84
+ return await fn();
85
+ } catch (error) {
86
+ this.handle(context, 'Operation failed', error);
87
+ return fallbackValue;
88
+ }
89
+ }
90
+
91
+ /**
92
+ * 安全执行函数并处理错误
93
+ * @param fn 函数
94
+ * @param context 错误上下文
95
+ * @param fallbackValue 错误时的返回值
96
+ * @returns 函数结果或 fallbackValue
97
+ */
98
+ static safeExecuteSync<T>(
99
+ fn: () => T,
100
+ context: string,
101
+ fallbackValue: T
102
+ ): T {
103
+ try {
104
+ return fn();
105
+ } catch (error) {
106
+ this.handle(context, 'Operation failed', error);
107
+ return fallbackValue;
108
+ }
109
+ }
110
+ }