id-scanner-lib 1.5.0 → 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 (72) hide show
  1. package/README.md +378 -59
  2. package/dist/id-scanner-lib.esm.js +195 -10
  3. package/dist/id-scanner-lib.esm.js.map +1 -1
  4. package/dist/id-scanner-lib.js +4812 -14709
  5. package/dist/id-scanner-lib.js.map +1 -1
  6. package/dist/types/browser-image-compression.d.ts +19 -0
  7. package/dist/types/tesseract.d.ts +280 -0
  8. package/package.json +21 -11
  9. package/src/core/camera-manager.ts +16 -1
  10. package/src/core/config.ts +37 -0
  11. package/src/core/errors.ts +3 -3
  12. package/src/core/event-emitter.test.ts +42 -0
  13. package/src/core/loading-state.test.ts +67 -0
  14. package/src/core/loading-state.ts +156 -0
  15. package/src/core/logger.test.ts +49 -0
  16. package/src/core/module-manager.ts +2 -4
  17. package/src/core/scanner-factory.ts +8 -9
  18. package/src/index.ts +3 -2
  19. package/src/modules/face/face-detector.ts +123 -66
  20. package/src/modules/id-card/anti-fake-detector.ts +2 -2
  21. package/src/modules/id-card/ocr-worker.ts +1 -1
  22. package/src/modules/qrcode/qr-code-scanner.ts +2 -1
  23. package/src/modules/qrcode/types.ts +111 -7
  24. package/src/types/common.test.ts +99 -0
  25. package/src/types/common.ts +166 -0
  26. package/src/utils/camera.test.ts +30 -0
  27. package/src/utils/camera.ts +4 -1
  28. package/src/utils/error-handler.test.ts +137 -0
  29. package/src/utils/error-handler.ts +110 -0
  30. package/src/utils/index.test.ts +186 -0
  31. package/src/utils/index.ts +3 -0
  32. package/src/utils/retry.test.ts +142 -0
  33. package/src/utils/retry.ts +282 -0
  34. package/src/utils/utils.test.ts +171 -0
  35. package/src/version.ts +1 -1
  36. package/dist/types/core/base-module.d.ts +0 -44
  37. package/dist/types/core/camera-manager.d.ts +0 -258
  38. package/dist/types/core/config.d.ts +0 -88
  39. package/dist/types/core/errors.d.ts +0 -111
  40. package/dist/types/core/event-emitter.d.ts +0 -55
  41. package/dist/types/core/logger.d.ts +0 -277
  42. package/dist/types/core/module-manager.d.ts +0 -78
  43. package/dist/types/core/plugin-manager.d.ts +0 -158
  44. package/dist/types/core/resource-manager.d.ts +0 -246
  45. package/dist/types/core/result.d.ts +0 -83
  46. package/dist/types/core/scanner-factory.d.ts +0 -93
  47. package/dist/types/index.bundle.d.ts +0 -1303
  48. package/dist/types/index.d.ts +0 -86
  49. package/dist/types/interfaces/external-types.d.ts +0 -174
  50. package/dist/types/interfaces/face-detection.d.ts +0 -293
  51. package/dist/types/interfaces/scanner-module.d.ts +0 -280
  52. package/dist/types/modules/face/face-detector.d.ts +0 -170
  53. package/dist/types/modules/face/index.d.ts +0 -56
  54. package/dist/types/modules/face/liveness-detector.d.ts +0 -177
  55. package/dist/types/modules/face/types.d.ts +0 -136
  56. package/dist/types/modules/id-card/anti-fake-detector.d.ts +0 -170
  57. package/dist/types/modules/id-card/id-card-detector.d.ts +0 -131
  58. package/dist/types/modules/id-card/index.d.ts +0 -89
  59. package/dist/types/modules/id-card/ocr-processor.d.ts +0 -110
  60. package/dist/types/modules/id-card/ocr-worker.d.ts +0 -31
  61. package/dist/types/modules/id-card/types.d.ts +0 -181
  62. package/dist/types/modules/qrcode/index.d.ts +0 -51
  63. package/dist/types/modules/qrcode/qr-code-scanner.d.ts +0 -64
  64. package/dist/types/modules/qrcode/types.d.ts +0 -67
  65. package/dist/types/utils/camera.d.ts +0 -81
  66. package/dist/types/utils/image-processing.d.ts +0 -176
  67. package/dist/types/utils/index.d.ts +0 -175
  68. package/dist/types/utils/performance.d.ts +0 -81
  69. package/dist/types/utils/resource-manager.d.ts +0 -53
  70. package/dist/types/utils/types.d.ts +0 -166
  71. package/dist/types/utils/worker.d.ts +0 -52
  72. package/dist/types/version.d.ts +0 -7
@@ -5,16 +5,65 @@
5
5
  */
6
6
 
7
7
  /**
8
- * 二维码检测结果
8
+ * 支持的条码格式
9
+ */
10
+ export enum BarcodeFormat {
11
+ /** QR码 */
12
+ QR_CODE = 'qrcode',
13
+ /** Code 128 */
14
+ CODE_128 = 'code_128',
15
+ /** Code 39 */
16
+ CODE_39 = 'code_39',
17
+ /** Code 93 */
18
+ CODE_93 = 'code_93',
19
+ /** EAN-13 */
20
+ EAN_13 = 'ean_13',
21
+ /** EAN-8 */
22
+ EAN_8 = 'ean_8',
23
+ /** UPC-A */
24
+ UPC_A = 'upc_a',
25
+ /** UPC-E */
26
+ UPC_E = 'upc_e',
27
+ /** ITF */
28
+ ITF = 'itf',
29
+ /** PDF417 */
30
+ PDF_417 = 'pdf_417',
31
+ /** DataMatrix */
32
+ DATA_MATRIX = 'data_matrix',
33
+ /** Aztec */
34
+ AZTEC = 'aztec',
35
+ /** Codabar */
36
+ CODABAR = 'codabar',
37
+ /** Industrial 2 of 5 */
38
+ INDUSTRIAL_2_OF_5 = 'industrial_2_of_5',
39
+ /** QR Code Micro */
40
+ QR_CODE_MICRO = 'qr_code_micro'
41
+ }
42
+
43
+ /**
44
+ * 默认支持的格式
45
+ */
46
+ export const DEFAULT_FORMATS = [
47
+ BarcodeFormat.QR_CODE,
48
+ BarcodeFormat.CODE_128,
49
+ BarcodeFormat.CODE_39,
50
+ BarcodeFormat.EAN_13
51
+ ];
52
+
53
+ /**
54
+ * 二维码/条码检测结果
9
55
  */
10
56
  export interface QRCodeResult {
11
- /** 二维码内容 */
57
+ /** 条码内容 */
12
58
  data: string;
13
59
 
14
- /** 二维码类型 */
60
+ /** 条码格式 */
61
+ barcodeFormat: BarcodeFormat;
62
+
63
+ /** 条码类型 (兼容旧版) */
15
64
  type?: string;
16
65
 
17
- /** 二维码边界框 */
66
+ /** 条码边界框 */
18
67
  boundingBox: {
19
68
  topLeft: { x: number; y: number };
20
69
  topRight: { x: number; y: number };
@@ -22,7 +71,7 @@ export interface QRCodeResult {
22
71
  bottomLeft: { x: number; y: number };
23
72
  };
24
73
 
25
- /** 二维码中心点 */
74
+ /** 条码中心点 */
26
75
  center: { x: number; y: number };
27
76
 
28
77
  /** 原始图像 */
@@ -30,6 +79,12 @@ export interface QRCodeResult {
30
79
 
31
80
  /** 置信度 */
32
81
  confidence?: number;
82
+
83
+ /** 原始数据 (解码后的字节) */
84
+ rawBytes?: Uint8Array;
85
+
86
+ /** 错误校正级别 (QR码) */
87
+ errorCorrectionLevel?: 'L' | 'M' | 'Q' | 'H';
33
88
  }
34
89
 
35
90
  /**
@@ -39,7 +94,7 @@ export interface QRCodeModuleOptions {
39
94
  /** 是否启用模块 */
40
95
  enabled?: boolean;
41
96
 
42
- /** 二维码扫描配置 */
97
+ /** 扫描配置 */
43
98
  scanner?: {
44
99
  /** 最小置信度 */
45
100
  minConfidence?: number;
@@ -49,6 +104,12 @@ export interface QRCodeModuleOptions {
49
104
 
50
105
  /** 是否返回原始图像 */
51
106
  returnImage?: boolean;
107
+
108
+ /** 扫描频率 (ms) */
109
+ scanFrequency?: number;
110
+
111
+ /** 启用扫描的格式 */
112
+ formats?: BarcodeFormat[];
52
113
  };
53
114
 
54
115
  /** 图像处理配置 */
@@ -61,5 +122,48 @@ export interface QRCodeModuleOptions {
61
122
 
62
123
  /** 二值化阈值 */
63
124
  threshold?: number;
125
+
126
+ /** 是否进行降噪 */
127
+ denoise?: boolean;
64
128
  };
65
- }
129
+ }
130
+
131
+ /**
132
+ * 实时扫描选项
133
+ */
134
+ export interface RealtimeScanOptions {
135
+ /** 视频元素 */
136
+ video: HTMLVideoElement;
137
+
138
+ /** 扫描回调 */
139
+ onResult: (result: QRCodeResult) => void;
140
+
141
+ /** 错误回调 */
142
+ onError?: (error: Error) => void;
143
+
144
+ /** 扫描频率 (ms) */
145
+ frequency?: number;
146
+
147
+ /** 是否连续扫描 */
148
+ continuous?: boolean;
149
+ }
150
+
151
+ /**
152
+ * 扫描统计信息
153
+ */
154
+ export interface ScanStats {
155
+ /** 总扫描次数 */
156
+ totalScans: number;
157
+
158
+ /** 成功次数 */
159
+ successfulScans: number;
160
+
161
+ /** 失败次数 */
162
+ failedScans: number;
163
+
164
+ /** 平均处理时间 (ms) */
165
+ avgProcessingTime: number;
166
+
167
+ /** 成功率 */
168
+ successRate: number;
169
+ }
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @file 通用类型测试
3
+ * @description 测试通用类型
4
+ */
5
+
6
+ import {
7
+ Rectangle,
8
+ Point,
9
+ Size,
10
+ ImageSource,
11
+ ModuleState,
12
+ CancellablePromise,
13
+ KeyValuePair
14
+ } from './common';
15
+
16
+ describe('Common Types', () => {
17
+ describe('Rectangle', () => {
18
+ it('should create rectangle', () => {
19
+ const rect: Rectangle = {
20
+ x: 10,
21
+ y: 20,
22
+ width: 100,
23
+ height: 50
24
+ };
25
+
26
+ expect(rect.x).toBe(10);
27
+ expect(rect.y).toBe(20);
28
+ expect(rect.width).toBe(100);
29
+ expect(rect.height).toBe(50);
30
+ });
31
+ });
32
+
33
+ describe('Point', () => {
34
+ it('should create point', () => {
35
+ const point: Point = {
36
+ x: 50,
37
+ y: 100
38
+ };
39
+
40
+ expect(point.x).toBe(50);
41
+ expect(point.y).toBe(100);
42
+ });
43
+ });
44
+
45
+ describe('Size', () => {
46
+ it('should create size', () => {
47
+ const size: Size = {
48
+ width: 1920,
49
+ height: 1080
50
+ };
51
+
52
+ expect(size.width).toBe(1920);
53
+ expect(size.height).toBe(1080);
54
+ });
55
+ });
56
+
57
+ describe('ModuleState', () => {
58
+ it('should have correct states', () => {
59
+ expect(ModuleState.UNINITIALIZED).toBe('uninitialized');
60
+ expect(ModuleState.INITIALIZING).toBe('initializing');
61
+ expect(ModuleState.INITIALIZED).toBe('initialized');
62
+ expect(ModuleState.RUNNING).toBe('running');
63
+ expect(ModuleState.PAUSED).toBe('paused');
64
+ expect(ModuleState.STOPPED).toBe('stopped');
65
+ expect(ModuleState.ERROR).toBe('error');
66
+ expect(ModuleState.DESTROYED).toBe('destroyed');
67
+ });
68
+ });
69
+
70
+ describe('CancellablePromise', () => {
71
+ it('should create cancellable promise', () => {
72
+ let cancelled = false;
73
+
74
+ const cp: CancellablePromise<string> = {
75
+ promise: new Promise((resolve) => {
76
+ setTimeout(() => resolve('done'), 100);
77
+ }),
78
+ cancel: () => {
79
+ cancelled = true;
80
+ }
81
+ };
82
+
83
+ expect(cp.promise).toBeInstanceOf(Promise);
84
+ expect(typeof cp.cancel).toBe('function');
85
+ });
86
+ });
87
+
88
+ describe('KeyValuePair', () => {
89
+ it('should create key value pair', () => {
90
+ const pair: KeyValuePair<string, number> = {
91
+ key: 'age',
92
+ value: 25
93
+ };
94
+
95
+ expect(pair.key).toBe('age');
96
+ expect(pair.value).toBe(25);
97
+ });
98
+ });
99
+ });
@@ -0,0 +1,166 @@
1
+ /**
2
+ * @file 通用类型定义
3
+ * @description 提供项目通用的类型定义
4
+ * @module types/common
5
+ */
6
+
7
+ /**
8
+ * 基础结果接口
9
+ */
10
+ export interface BaseResult<T = unknown> {
11
+ /** 是否成功 */
12
+ success: boolean;
13
+ /** 结果数据 */
14
+ data?: T;
15
+ /** 错误信息 */
16
+ error?: string;
17
+ /** 错误码 */
18
+ code?: string;
19
+ }
20
+
21
+ /**
22
+ * 分页结果接口
23
+ */
24
+ export interface PaginatedResult<T> {
25
+ /** 数据列表 */
26
+ items: T[];
27
+ /** 总数 */
28
+ total: number;
29
+ /** 当前页码 */
30
+ page: number;
31
+ /** 每页大小 */
32
+ pageSize: number;
33
+ /** 是否有下一页 */
34
+ hasMore: boolean;
35
+ }
36
+
37
+ /**
38
+ * 通用配置接口
39
+ */
40
+ export interface GenericConfig {
41
+ /** 启用状态 */
42
+ enabled?: boolean;
43
+ /** 调试模式 */
44
+ debug?: boolean;
45
+ /** 超时时间(ms) */
46
+ timeout?: number;
47
+ /** 重试次数 */
48
+ retries?: number;
49
+ }
50
+
51
+ /**
52
+ * 回调函数类型
53
+ */
54
+ export type Callback<T = unknown> = (error?: Error, result?: T) => void;
55
+
56
+ /**
57
+ * 异步回调函数类型
58
+ */
59
+ export type AsyncCallback<T = unknown> = (error?: Error, result?: T) => Promise<void>;
60
+
61
+ /**
62
+ * 可取消的 Promise
63
+ */
64
+ export interface CancellablePromise<T> {
65
+ /** Promise 对象 */
66
+ promise: Promise<T>;
67
+ /** 取消函数 */
68
+ cancel: () => void;
69
+ }
70
+
71
+ /**
72
+ * 事件监听器类型
73
+ */
74
+ export type EventListener<T = unknown> = (event: T) => void;
75
+
76
+ /**
77
+ * 生命周期钩子
78
+ */
79
+ export interface LifecycleHooks {
80
+ /** 初始化前 */
81
+ onBeforeInit?: () => void | Promise<void>;
82
+ /** 初始化后 */
83
+ onAfterInit?: () => void | Promise<void>;
84
+ /** 销毁前 */
85
+ onBeforeDestroy?: () => void | Promise<void>;
86
+ /** 销毁后 */
87
+ onAfterDestroy?: () => void | Promise<void>;
88
+ }
89
+
90
+ /**
91
+ * 模块状态
92
+ */
93
+ export enum ModuleState {
94
+ /** 未初始化 */
95
+ UNINITIALIZED = 'uninitialized',
96
+ /** 初始化中 */
97
+ INITIALIZING = 'initializing',
98
+ /** 已初始化 */
99
+ INITIALIZED = 'initialized',
100
+ /** 运行中 */
101
+ RUNNING = 'running',
102
+ /** 已暂停 */
103
+ PAUSED = 'paused',
104
+ /** 已停止 */
105
+ STOPPED = 'stopped',
106
+ /** 错误 */
107
+ ERROR = 'error',
108
+ /** 已销毁 */
109
+ DESTROYED = 'destroyed'
110
+ }
111
+
112
+ /**
113
+ * 检测结果基类
114
+ */
115
+ export interface DetectionResultBase {
116
+ /** 置信度 (0-1) */
117
+ confidence: number;
118
+ /** 边界框 */
119
+ boundingBox?: {
120
+ x: number;
121
+ y: number;
122
+ width: number;
123
+ height: number;
124
+ };
125
+ /** 时间戳 */
126
+ timestamp: number;
127
+ }
128
+
129
+ /**
130
+ * 图像源类型
131
+ */
132
+ export type ImageSource = string | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | ImageData | Blob;
133
+
134
+ /**
135
+ * 矩形区域
136
+ */
137
+ export interface Rectangle {
138
+ x: number;
139
+ y: number;
140
+ width: number;
141
+ height: number;
142
+ }
143
+
144
+ /**
145
+ * 点
146
+ */
147
+ export interface Point {
148
+ x: number;
149
+ y: number;
150
+ }
151
+
152
+ /**
153
+ * 尺寸
154
+ */
155
+ export interface Size {
156
+ width: number;
157
+ height: number;
158
+ }
159
+
160
+ /**
161
+ * 键值对
162
+ */
163
+ export interface KeyValuePair<K = string, V = unknown> {
164
+ key: K;
165
+ value: V;
166
+ }
@@ -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
+ });