id-scanner-lib 1.7.0 → 2.0.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "id-scanner-lib",
3
- "version": "1.7.0",
3
+ "version": "2.0.0",
4
4
  "description": "Browser-based ID card, QR code, and face recognition scanner with liveness detection",
5
5
  "main": "dist/id-scanner-lib.js",
6
6
  "module": "dist/id-scanner-lib.esm.js",
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @file Compat Index
3
+ * @description Compatibility layer for v1 API
4
+ * @module compat
5
+ */
6
+
7
+ export {};
@@ -0,0 +1,84 @@
1
+ /**
2
+ * @file V1 Adapter (Compatibility Layer)
3
+ * @description Provides backward compatibility with v1 IDScanner API
4
+ * @module compat/v1-adapter
5
+ */
6
+
7
+ import { Scanner, ScannerConfig } from '../core/scanner';
8
+ import { EventEmitter } from '../core/event-emitter';
9
+
10
+ /**
11
+ * V1 IDScanner configuration
12
+ */
13
+ export interface IDScannerConfig {
14
+ /** Debug mode */
15
+ debug?: boolean;
16
+ /** Callback when faces are detected */
17
+ onFaceDetected?: (faces: any[]) => void;
18
+ /** Callback on error */
19
+ onError?: (error: Error) => void;
20
+ }
21
+
22
+ /**
23
+ * IDScanner class - provides v1 API compatibility
24
+ * Wraps the new Scanner class with the old IDScanner interface
25
+ */
26
+ export class IDScanner {
27
+ private _scanner: Scanner;
28
+ private _config: IDScannerConfig;
29
+ private _eventEmitter: EventEmitter;
30
+
31
+ /**
32
+ * Create a new IDScanner instance
33
+ * @param config Configuration
34
+ */
35
+ constructor(config: IDScannerConfig = {}) {
36
+ this._config = config;
37
+ this._scanner = new Scanner({ debug: config.debug });
38
+ this._eventEmitter = new EventEmitter();
39
+ }
40
+
41
+ /**
42
+ * Initialize the scanner
43
+ */
44
+ async initialize(): Promise<void> {
45
+ await this._scanner.initialize();
46
+ }
47
+
48
+ /**
49
+ * Start face recognition on a video element
50
+ * @param video Video element to process
51
+ */
52
+ async startFaceRecognition(video: HTMLVideoElement): Promise<void> {
53
+ const faces = await this._scanner.detectFace(video);
54
+ if (this._config.onFaceDetected) {
55
+ this._config.onFaceDetected(faces);
56
+ }
57
+ this._eventEmitter.emit('faceDetected', faces);
58
+ }
59
+
60
+ /**
61
+ * Stop the scanner and release resources
62
+ */
63
+ async stop(): Promise<void> {
64
+ await this._scanner.destroy();
65
+ }
66
+
67
+ /**
68
+ * Register an event handler
69
+ * @param event Event name
70
+ * @param handler Event handler
71
+ */
72
+ on(event: string, handler: (data?: any) => void): void {
73
+ this._eventEmitter.on(event, handler);
74
+ }
75
+
76
+ /**
77
+ * Unregister an event handler
78
+ * @param event Event name
79
+ * @param handler Event handler
80
+ */
81
+ off(event: string, handler: (data?: any) => void): void {
82
+ this._eventEmitter.off(event, handler);
83
+ }
84
+ }
@@ -1,37 +1,23 @@
1
1
  /**
2
- * @file 配置管理器
3
- * @description 提供全局配置管理功能
2
+ * @file 配置管理器 + Scanner 配置
3
+ * @description 提供全局配置管理功能 + Scanner v2.0 配置接口
4
4
  * @module core/config
5
5
  */
6
6
 
7
- /**
8
- * 配置管理器
9
- * 负责存储和管理应用程序的配置
10
- */
7
+ // ============================================================
8
+ // 原有 ConfigManager(保持向后兼容)
9
+ // ============================================================
10
+
11
11
  export class ConfigManager {
12
- /** 单例实例 */
13
12
  private static instance: ConfigManager;
14
-
15
- /** 配置存储 */
16
13
  private config: Record<string, any> = {};
17
-
18
- /** 配置变更回调 */
19
14
  private changeCallbacks: Map<string, Array<(value: any, oldValue: any) => void>> = new Map();
20
-
21
- /** 初始化状态 */
22
15
  private initialized = false;
23
-
24
- /**
25
- * 私有构造函数
26
- */
16
+
27
17
  private constructor() {
28
- // 设置默认配置
29
18
  this._resetDefaults();
30
19
  }
31
-
32
- /**
33
- * 获取单例实例
34
- */
20
+
35
21
  public static getInstance(): ConfigManager {
36
22
  if (!ConfigManager.instance) {
37
23
  ConfigManager.instance = new ConfigManager();
@@ -39,285 +25,145 @@ export class ConfigManager {
39
25
  return ConfigManager.instance;
40
26
  }
41
27
 
42
- /**
43
- * 重置单例实例(主要用于测试)
44
- */
45
28
  public static resetInstance(): void {
46
29
  ConfigManager.instance = undefined as any;
47
30
  }
48
31
 
49
- /**
50
- * 重置为默认配置
51
- */
52
32
  private _resetDefaults(): void {
53
33
  this.config = {
54
34
  debug: false,
55
35
  logLevel: 'info',
56
- camera: {
57
- resolution: {
58
- width: 1280,
59
- height: 720
60
- },
61
- frameRate: 30,
62
- facingMode: 'environment'
36
+ modelPath: '/models',
37
+ maxRetries: 3,
38
+ retryDelay: 1000,
39
+ detectionInterval: 100,
40
+ face: {
41
+ enabled: true,
42
+ confidenceThreshold: 0.5,
43
+ maxFaces: 10,
44
+ },
45
+ idCard: {
46
+ enabled: false,
47
+ },
48
+ qr: {
49
+ enabled: false,
63
50
  },
64
- performance: {
65
- useCache: true
66
- }
67
51
  };
68
52
  this.initialized = true;
69
53
  }
70
-
71
- /**
72
- * 获取配置值
73
- * @param key 配置键,支持点号分隔的路径
74
- * @param defaultValue 默认值
75
- */
76
- get<T = any>(key: string, defaultValue?: T): T {
77
- const value = this.getNestedValue(this.config, key);
78
- return (value !== undefined) ? value : (defaultValue as T);
79
- }
80
-
81
- /**
82
- * 设置配置值
83
- * @param key 配置键,支持点号分隔的路径
84
- * @param value 配置值
85
- */
86
- set<T = any>(key: string, value: T): void {
87
- const oldValue = this.get(key);
88
-
89
- // 如果值相同,不做任何事
90
- if (oldValue === value) {
91
- return;
54
+
55
+ public get<T = any>(key: string, defaultValue?: T): T {
56
+ const keys = key.split('.');
57
+ let value: any = this.config;
58
+ for (const k of keys) {
59
+ value = value?.[k];
92
60
  }
93
-
94
- this.setNestedValue(this.config, key, value);
95
-
96
- // 触发变更回调
97
- this.triggerChangeCallbacks(key, value, oldValue);
61
+ return (value !== undefined ? value : defaultValue) as T;
98
62
  }
99
-
100
- /**
101
- * 批量更新配置
102
- * @param config 配置对象
103
- */
104
- updateConfig(config: Record<string, any>): void {
105
- Object.entries(config).forEach(([key, value]) => {
106
- this.set(key, value);
107
- });
108
- }
109
-
110
- /**
111
- * 重置为默认配置
112
- */
113
- reset(): void {
114
- const oldConfig = { ...this.config };
115
-
116
- // 使用私有 reset 方法重建默认配置
117
- this.config = {
118
- debug: false,
119
- logLevel: 'info',
120
- camera: {
121
- resolution: {
122
- width: 1280,
123
- height: 720
124
- },
125
- frameRate: 30,
126
- facingMode: 'environment'
127
- },
128
- performance: {
129
- useCache: true
130
- }
131
- };
132
-
133
- // 触发所有回调
134
- Object.keys(oldConfig).forEach(key => {
135
- this.triggerChangeCallbacks(key, this.get(key), oldConfig[key]);
136
- });
63
+
64
+ public set(key: string, value: any): void {
65
+ const keys = key.split('.');
66
+ let target: any = this.config;
67
+ for (let i = 0; i < keys.length - 1; i++) {
68
+ if (!target[keys[i]]) target[keys[i]] = {};
69
+ target = target[keys[i]];
70
+ }
71
+ const oldValue = target[keys[keys.length - 1]];
72
+ target[keys[keys.length - 1]] = value;
73
+ const callbacks = this.changeCallbacks.get(key);
74
+ if (callbacks) {
75
+ callbacks.forEach(cb => cb(value, oldValue));
76
+ }
137
77
  }
138
-
139
- /**
140
- * 注册配置变更回调
141
- * @param key 配置键
142
- * @param callback 回调函数
143
- */
144
- onConfigChange<T = any>(key: string, callback: (value: T, oldValue: T) => void): void {
78
+
79
+ public onChange(key: string, callback: (value: any, oldValue: any) => void): void {
145
80
  if (!this.changeCallbacks.has(key)) {
146
81
  this.changeCallbacks.set(key, []);
147
82
  }
148
-
149
83
  this.changeCallbacks.get(key)!.push(callback);
150
84
  }
151
-
152
- /**
153
- * 移除配置变更回调
154
- * @param key 配置键
155
- * @param callback 特定回调函数,如不提供则移除所有
156
- */
157
- offConfigChange<T = any>(key: string, callback?: (value: T, oldValue: T) => void): void {
158
- if (!this.changeCallbacks.has(key)) {
159
- return;
160
- }
161
-
162
- if (callback) {
163
- // 移除特定回调
164
- const callbacks = this.changeCallbacks.get(key)!;
165
- const index = callbacks.indexOf(callback as any);
166
- if (index !== -1) {
167
- callbacks.splice(index, 1);
168
- }
169
-
170
- // 如果没有回调,删除键
171
- if (callbacks.length === 0) {
172
- this.changeCallbacks.delete(key);
173
- }
174
- } else {
175
- // 移除所有回调
176
- this.changeCallbacks.delete(key);
177
- }
178
- }
179
-
180
- /**
181
- * 获取嵌套值
182
- * @param obj 对象
183
- * @param path 路径
184
- */
185
- private getNestedValue(obj: Record<string, any>, path: string): any {
186
- // 处理根路径
187
- if (!path) {
188
- return obj;
189
- }
190
-
191
- // 处理嵌套路径
192
- const parts = path.split('.');
193
- let current = obj;
194
-
195
- for (const part of parts) {
196
- if (current === undefined || current === null) {
197
- return undefined;
198
- }
199
-
200
- current = current[part];
201
- }
202
-
203
- return current;
204
- }
205
-
206
- /**
207
- * 设置嵌套值
208
- * @param obj 对象
209
- * @param path 路径
210
- * @param value 值
211
- */
212
- private setNestedValue(obj: Record<string, any>, path: string, value: any): void {
213
- // 处理根路径
214
- if (!path) {
215
- return;
216
- }
217
-
218
- // 处理嵌套路径
219
- const parts = path.split('.');
220
- let current = obj;
221
-
222
- // 遍历路径,直到倒数第二部分
223
- for (let i = 0; i < parts.length - 1; i++) {
224
- const part = parts[i];
225
-
226
- // 如果不存在,创建新对象
227
- if (current[part] === undefined || current[part] === null || typeof current[part] !== 'object') {
228
- current[part] = {};
229
- }
230
-
231
- current = current[part];
232
- }
233
-
234
- // 设置最终值
235
- current[parts[parts.length - 1]] = value;
85
+
86
+ /** @deprecated Use onChange instead */
87
+ public onConfigChange<T = any>(key: string, callback: (value: T, oldValue: T) => void): void {
88
+ this.onChange(key, callback);
236
89
  }
237
-
238
- /**
239
- * 触发变更回调
240
- * @param key 配置键
241
- * @param value 新值
242
- * @param oldValue 旧值
243
- */
244
- private triggerChangeCallbacks(key: string, value: any, oldValue: any): void {
245
- // 触发特定键的回调
246
- if (this.changeCallbacks.has(key)) {
247
- const callbacks = this.changeCallbacks.get(key)!;
248
- callbacks.forEach(callback => {
249
- try {
250
- callback(value, oldValue);
251
- } catch (error) {
252
- console.error(`Error in config change callback for key ${key}:`, error);
253
- }
254
- });
255
- }
256
-
257
- // 触发父路径的回调
258
- const parts = key.split('.');
259
- while (parts.length > 1) {
260
- parts.pop();
261
- const parentKey = parts.join('.');
262
-
263
- if (this.changeCallbacks.has(parentKey)) {
264
- const parentValue = this.get(parentKey);
265
- this.changeCallbacks.get(parentKey)!.forEach(callback => {
266
- try {
267
- callback(parentValue, parentValue);
268
- } catch (error) {
269
- console.error(`Error in config change callback for parent key ${parentKey}:`, error);
270
- }
271
- });
272
- }
90
+
91
+ public removeChangeCallback(key: string, callback: (value: any, oldValue: any) => void): void {
92
+ const callbacks = this.changeCallbacks.get(key);
93
+ if (callbacks) {
94
+ const index = callbacks.indexOf(callback);
95
+ if (index > -1) callbacks.splice(index, 1);
273
96
  }
274
97
  }
275
98
 
276
- /**
277
- * 检查模块是否启用
278
- * @param moduleName 模块名称
279
- */
280
- public isModuleEnabled(moduleName: string): boolean {
281
- const key = `modules.${moduleName}.enabled`;
282
- return this.get(key) ?? false;
99
+ public reset(): void {
100
+ this.config = {};
101
+ this._resetDefaults();
283
102
  }
284
103
  }
285
104
 
105
+ // ============================================================
106
+ // Scanner v2.0 配置接口
107
+ // ============================================================
108
+
286
109
  /**
287
- * 全局配置接口
110
+ * Scanner configuration interface (v2.0)
288
111
  */
289
- export interface GlobalConfig {
290
- /** 版本号 */
291
- version: string;
292
- /** 调试模式 */
293
- debug: boolean;
294
- /** 日志级别 */
295
- logLevel: string;
296
- /** 摄像头配置 */
297
- camera: {
298
- resolution: { width: number; height: number };
299
- frameRate: number;
300
- facingMode: string;
112
+ export interface ScannerConfig {
113
+ debug?: boolean;
114
+ modules?: {
115
+ face?: boolean;
116
+ faceComparator?: boolean;
117
+ faceLiveness?: boolean;
118
+ idCard?: boolean;
119
+ qr?: boolean;
301
120
  };
302
- /** 性能配置 */
303
- performance: {
304
- useCache: boolean;
121
+ performance?: {
122
+ maxCanvasWidth?: number;
123
+ useWorker?: boolean;
124
+ lazyLoad?: boolean;
305
125
  };
306
- /** 模块配置 */
307
- modules: {
308
- face: { enabled: boolean };
309
- idcard: { enabled: boolean };
310
- qrcode: { enabled: boolean };
126
+ }
127
+
128
+ /**
129
+ * Scanner module interface
130
+ * All modules must implement this interface
131
+ */
132
+ export interface ScannerModule {
133
+ initialize(): Promise<void>;
134
+ destroy(): Promise<void>;
135
+ }
136
+
137
+ /**
138
+ * Image source types
139
+ */
140
+ export type ImageSource = HTMLVideoElement | HTMLCanvasElement | HTMLImageElement | ImageData | string;
141
+
142
+ /**
143
+ * Face detection result
144
+ */
145
+ export interface Face {
146
+ box: {
147
+ x: number;
148
+ y: number;
149
+ width: number;
150
+ height: number;
151
+ };
152
+ confidence: number;
153
+ keypoints?: {
154
+ leftEye?: { x: number; y: number };
155
+ rightEye?: { x: number; y: number };
156
+ nose?: { x: number; y: number };
157
+ leftMouth?: { x: number; y: number };
158
+ rightMouth?: { x: number; y: number };
311
159
  };
312
- }
160
+ embedding?: number[];
161
+ }
313
162
 
314
163
  /**
315
- * 模块配置接口
316
- * 定义所有模块共享的基础配置属性
164
+ * Module configuration
317
165
  */
318
166
  export interface ModuleConfig {
319
- /** 是否启用该模块 */
320
- enabled: boolean;
321
- /** 其他模块特定配置 */
167
+ enabled?: boolean;
322
168
  [key: string]: any;
323
- }
169
+ }