id-scanner-lib
Version:
Browser-based ID card, QR code, and face recognition scanner with liveness detection
170 lines (151 loc) • 4.18 kB
text/typescript
/**
* @file 配置管理器 + Scanner 配置
* @description 提供全局配置管理功能 + Scanner v2.0 配置接口
* @module core/config
*/
// ============================================================
// 原有 ConfigManager(保持向后兼容)
// ============================================================
export class ConfigManager {
private static instance: ConfigManager;
private config: Record<string, any> = {};
private changeCallbacks: Map<string, Array<(value: any, oldValue: any) => void>> = new Map();
private initialized = false;
private constructor() {
this._resetDefaults();
}
public static getInstance(): ConfigManager {
if (!ConfigManager.instance) {
ConfigManager.instance = new ConfigManager();
}
return ConfigManager.instance;
}
public static resetInstance(): void {
ConfigManager.instance = undefined as any;
}
private _resetDefaults(): void {
this.config = {
debug: false,
logLevel: 'info',
modelPath: '/models',
maxRetries: 3,
retryDelay: 1000,
detectionInterval: 100,
face: {
enabled: true,
confidenceThreshold: 0.5,
maxFaces: 10,
},
idCard: {
enabled: false,
},
qr: {
enabled: false,
},
};
this.initialized = true;
}
public get<T = any>(key: string, defaultValue?: T): T {
const keys = key.split('.');
let value: any = this.config;
for (const k of keys) {
value = value?.[k];
}
return (value !== undefined ? value : defaultValue) as T;
}
public set(key: string, value: any): void {
const keys = key.split('.');
let target: any = this.config;
for (let i = 0; i < keys.length - 1; i++) {
if (!target[keys[i]]) target[keys[i]] = {};
target = target[keys[i]];
}
const oldValue = target[keys[keys.length - 1]];
target[keys[keys.length - 1]] = value;
const callbacks = this.changeCallbacks.get(key);
if (callbacks) {
callbacks.forEach(cb => cb(value, oldValue));
}
}
public onChange(key: string, callback: (value: any, oldValue: any) => void): void {
if (!this.changeCallbacks.has(key)) {
this.changeCallbacks.set(key, []);
}
this.changeCallbacks.get(key)!.push(callback);
}
/** @deprecated Use onChange instead */
public onConfigChange<T = any>(key: string, callback: (value: T, oldValue: T) => void): void {
this.onChange(key, callback);
}
public removeChangeCallback(key: string, callback: (value: any, oldValue: any) => void): void {
const callbacks = this.changeCallbacks.get(key);
if (callbacks) {
const index = callbacks.indexOf(callback);
if (index > -1) callbacks.splice(index, 1);
}
}
public reset(): void {
this.config = {};
this._resetDefaults();
}
}
// ============================================================
// Scanner v2.0 配置接口
// ============================================================
/**
* Scanner configuration interface (v2.0)
*/
export interface ScannerConfig {
debug?: boolean;
modules?: {
face?: boolean;
faceComparator?: boolean;
faceLiveness?: boolean;
idCard?: boolean;
qr?: boolean;
};
performance?: {
maxCanvasWidth?: number;
useWorker?: boolean;
lazyLoad?: boolean;
};
}
/**
* Scanner module interface
* All modules must implement this interface
*/
export interface ScannerModule {
initialize(): Promise<void>;
destroy(): Promise<void>;
}
/**
* Image source types
*/
export type ImageSource = HTMLVideoElement | HTMLCanvasElement | HTMLImageElement | ImageData | string;
/**
* Face detection result
*/
export interface Face {
box: {
x: number;
y: number;
width: number;
height: number;
};
confidence: number;
keypoints?: {
leftEye?: { x: number; y: number };
rightEye?: { x: number; y: number };
nose?: { x: number; y: number };
leftMouth?: { x: number; y: number };
rightMouth?: { x: number; y: number };
};
embedding?: number[];
}
/**
* Module configuration
*/
export interface ModuleConfig {
enabled?: boolean;
[key: string]: any;
}