id-scanner-lib 1.6.7 → 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.
Files changed (48) hide show
  1. package/dist/id-scanner-lib.esm.js +994 -1139
  2. package/dist/id-scanner-lib.esm.js.map +1 -1
  3. package/dist/id-scanner-lib.js +995 -1144
  4. package/dist/id-scanner-lib.js.map +1 -1
  5. package/package.json +1 -1
  6. package/src/compat/index.ts +7 -0
  7. package/src/compat/v1-adapter.ts +84 -0
  8. package/src/core/camera-manager.ts +43 -76
  9. package/src/core/camera-stream-manager.ts +318 -0
  10. package/src/core/config.ts +113 -267
  11. package/src/core/errors.ts +68 -117
  12. package/src/core/logger.ts +158 -81
  13. package/src/core/resource-manager.ts +150 -0
  14. package/src/core/scanner.ts +109 -0
  15. package/src/core/utils/browser.ts +7 -0
  16. package/src/core/utils/canvas-pool.ts +171 -0
  17. package/src/core/utils/canvas.ts +7 -0
  18. package/src/core/utils/image.ts +7 -0
  19. package/src/core/utils/index.ts +9 -0
  20. package/src/core/utils/resource-manager.ts +155 -0
  21. package/src/core/utils/validate.ts +7 -0
  22. package/src/core/utils/worker.ts +130 -0
  23. package/src/modules/face/comparator/comparator.ts +45 -0
  24. package/src/modules/face/comparator/index.ts +1 -0
  25. package/src/modules/face/detector/detector.ts +83 -0
  26. package/src/modules/face/detector/index.ts +2 -0
  27. package/src/modules/face/detector/types.ts +80 -0
  28. package/src/modules/face/face-comparator.ts +150 -0
  29. package/src/modules/face/face-detector-options.ts +104 -0
  30. package/src/modules/face/face-detector.ts +121 -376
  31. package/src/modules/face/face-detector.ts.bak +991 -0
  32. package/src/modules/face/face-model-loader.ts +222 -0
  33. package/src/modules/face/face-result-converter.ts +225 -0
  34. package/src/modules/face/face-tracker.ts +207 -0
  35. package/src/modules/face/liveness/index.ts +7 -0
  36. package/src/modules/face/liveness-detector.ts +2 -2
  37. package/src/modules/face/tracker/index.ts +7 -0
  38. package/src/modules/id-card/anti-fake/index.ts +7 -0
  39. package/src/modules/id-card/detector/index.ts +7 -0
  40. package/src/modules/id-card/id-card-text-parser.ts +151 -0
  41. package/src/modules/id-card/ocr-processor.ts +20 -257
  42. package/src/modules/id-card/ocr-worker.ts +2 -183
  43. package/src/modules/id-card/parser/index.ts +7 -0
  44. package/src/modules/qr/scanner/index.ts +7 -0
  45. package/src/utils/canvas-pool.ts +273 -0
  46. package/src/utils/edge-detector.ts +232 -0
  47. package/src/utils/image-processing.ts +92 -419
  48. package/src/utils/index.ts +1 -0
@@ -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
+ }
@@ -1,174 +1,125 @@
1
1
  /**
2
- * @file 错误处理模块
3
- * @description 定义ID-Scanner-Lib的错误类层次结构
2
+ * @file Scanner Errors
3
+ * @description Error classes for Scanner
4
4
  * @module core/errors
5
5
  */
6
6
 
7
7
  /**
8
- * ID-Scanner-Lib 基础错误类
9
- * 所有库特定错误的基类
8
+ * Scanner specific error
10
9
  */
11
- export class IDScannerError extends Error {
12
- /** 错误代码 */
10
+ export class ScannerError extends Error {
11
+ /**
12
+ * Error code
13
+ */
13
14
  public code: string;
14
- /** 错误原因 */
15
- public cause?: Error;
15
+ /**
16
+ * Module that threw the error
17
+ */
18
+ public module?: string;
16
19
 
17
20
  /**
18
- * 构造函数
19
- * @param message 错误消息
20
- * @param options 错误选项
21
+ * Create a ScannerError
22
+ * @param message Error message
23
+ * @param code Error code
24
+ * @param module Module name
21
25
  */
22
- constructor(message: string, options?: { code?: string; cause?: Error }) {
26
+ constructor(message: string, code: string, module?: string) {
23
27
  super(message);
24
-
25
- // 设置错误名称
26
- this.name = this.constructor.name;
27
-
28
- // 设置错误代码
29
- this.code = options?.code || 'UNKNOWN_ERROR';
30
-
31
- // 设置错误原因
32
- this.cause = options?.cause;
33
-
34
- // 捕获堆栈 (Node.js专有,浏览器环境忽略)
35
- if (typeof (Error as any).captureStackTrace === 'function') {
36
- (Error as any).captureStackTrace(this, this.constructor);
37
- }
28
+ this.name = 'ScannerError';
29
+ this.code = code;
30
+ this.module = module;
38
31
  }
39
32
  }
40
33
 
41
34
  /**
42
- * 初始化错误
43
- * 当库初始化失败时抛出
35
+ * Camera access error
44
36
  */
45
- export class InitializationError extends IDScannerError {
46
- constructor(message: string, details?: string) {
47
- super(`初始化失败: ${message}${details ? ` (${details})` : ''}`, { code: 'INIT_FAILED' });
48
- this.name = 'InitializationError';
37
+ export class CameraAccessError extends Error {
38
+ constructor(message = 'Camera access denied') {
39
+ super(message);
40
+ this.name = 'CameraAccessError';
49
41
  }
50
42
  }
51
43
 
52
44
  /**
53
- * 设备错误
54
- * 当访问硬件设备(如摄像头)失败时抛出
45
+ * Device error
55
46
  */
56
- export class DeviceError extends IDScannerError {
57
- constructor(message: string) {
58
- super(`设备错误: ${message}`, { code: 'DEVICE_ERROR' });
47
+ export class DeviceError extends Error {
48
+ constructor(message = 'Device error') {
49
+ super(message);
59
50
  this.name = 'DeviceError';
60
51
  }
61
52
  }
62
53
 
63
54
  /**
64
- * 摄像头访问错误
65
- * 当无法访问或启动摄像头时抛出
55
+ * Resource load error
66
56
  */
67
- export class CameraAccessError extends IDScannerError {
68
- constructor(message: string, options?: { code?: string; cause?: Error }) {
69
- super(`摄像头访问失败: ${message}`, {
70
- code: options?.code || 'CAMERA_ACCESS_FAILED',
71
- cause: options?.cause
72
- });
73
- this.name = 'CameraAccessError';
57
+ export class ResourceLoadError extends Error {
58
+ public readonly id?: string;
59
+ constructor(message = 'Failed to load resource', id?: string) {
60
+ super(message);
61
+ this.name = 'ResourceLoadError';
62
+ this.id = id;
74
63
  }
75
64
  }
76
65
 
77
66
  /**
78
- * 人脸检测错误
79
- * 当人脸检测过程失败时抛出
67
+ * Face detection error
80
68
  */
81
- export class FaceDetectionError extends IDScannerError {
82
- constructor(message: string) {
83
- super(`人脸检测失败: ${message}`, { code: 'FACE_DETECTION_FAILED' });
69
+ export class FaceDetectionError extends Error {
70
+ constructor(message = 'Face detection failed') {
71
+ super(message);
84
72
  this.name = 'FaceDetectionError';
85
73
  }
86
74
  }
87
75
 
88
76
  /**
89
- * 人脸比对错误
90
- * 当人脸比对过程失败时抛出
77
+ * Face comparison error
91
78
  */
92
- export class FaceComparisonError extends IDScannerError {
93
- constructor(message: string) {
94
- super(`人脸比对失败: ${message}`, { code: 'FACE_COMPARISON_FAILED' });
79
+ export class FaceComparisonError extends Error {
80
+ constructor(message = 'Face comparison failed') {
81
+ super(message);
95
82
  this.name = 'FaceComparisonError';
96
83
  }
97
84
  }
98
85
 
99
86
  /**
100
- * 活体检测错误
101
- * 当活体检测过程失败时抛出
102
- */
103
- export class LivenessDetectionError extends IDScannerError {
104
- constructor(message: string) {
105
- super(`活体检测失败: ${message}`, { code: 'LIVENESS_DETECTION_FAILED' });
106
- this.name = 'LivenessDetectionError';
107
- }
108
- }
109
-
110
- /**
111
- * OCR识别错误
112
- * 当OCR文字识别失败时抛出
87
+ * Initialization error
113
88
  */
114
- export class OCRProcessingError extends IDScannerError {
115
- constructor(message: string) {
116
- super(`OCR处理失败: ${message}`, { code: 'OCR_PROCESSING_FAILED' });
117
- this.name = 'OCRProcessingError';
118
- }
119
- }
120
-
121
- /**
122
- * 二维码扫描错误
123
- * 当二维码扫描失败时抛出
124
- */
125
- export class QRScanError extends IDScannerError {
126
- constructor(message: string) {
127
- super(`二维码扫描失败: ${message}`, { code: 'QR_SCAN_FAILED' });
128
- this.name = 'QRScanError';
129
- }
130
- }
131
-
132
- /**
133
- * 身份证检测错误
134
- * 当身份证检测失败时抛出
135
- */
136
- export class IDCardDetectionError extends IDScannerError {
137
- constructor(message: string) {
138
- super(`身份证检测失败: ${message}`, { code: 'ID_CARD_DETECTION_FAILED' });
139
- this.name = 'IDCardDetectionError';
89
+ export class InitializationError extends Error {
90
+ constructor(message = 'Initialization failed') {
91
+ super(message);
92
+ this.name = 'InitializationError';
140
93
  }
141
94
  }
142
95
 
143
96
  /**
144
- * 资源加载错误
145
- * 当无法加载必要资源(如模型)时抛出
97
+ * Liveness detection error
146
98
  */
147
- export class ResourceLoadError extends IDScannerError {
148
- constructor(resource: string, reason: string) {
149
- super(`无法加载资源 ${resource}: ${reason}`, { code: 'RESOURCE_LOAD_FAILED' });
150
- this.name = 'ResourceLoadError';
99
+ export class LivenessDetectionError extends Error {
100
+ constructor(message = 'Liveness detection failed') {
101
+ super(message);
102
+ this.name = 'LivenessDetectionError';
151
103
  }
152
104
  }
153
105
 
154
106
  /**
155
- * 参数错误
156
- * 当提供的参数无效时抛出
107
+ * Error codes for Scanner
157
108
  */
158
- export class InvalidArgumentError extends IDScannerError {
159
- constructor(paramName: string, reason: string) {
160
- super(`无效的参数 ${paramName}: ${reason}`, { code: 'INVALID_ARGUMENT' });
161
- this.name = 'InvalidArgumentError';
162
- }
163
- }
109
+ export const ErrorCodes = {
110
+ /** Scanner not initialized */
111
+ NOT_INITIALIZED: 'SCANNER_001',
112
+ /** Module not found */
113
+ MODULE_NOT_FOUND: 'SCANNER_002',
114
+ /** Detection failed */
115
+ DETECTION_FAILED: 'SCANNER_003',
116
+ /** Camera access denied */
117
+ CAMERA_ACCESS_DENIED: 'CAMERA_001',
118
+ /** Camera not available */
119
+ CAMERA_NOT_AVAILABLE: 'CAMERA_002',
120
+ } as const;
164
121
 
165
122
  /**
166
- * 不支持错误
167
- * 当尝试使用不支持的功能或当前环境无法使用的功能时抛出
123
+ * Type for error codes
168
124
  */
169
- export class NotSupportedError extends IDScannerError {
170
- constructor(feature: string) {
171
- super(`不支持的功能: ${feature}`, { code: 'NOT_SUPPORTED' });
172
- this.name = 'NotSupportedError';
173
- }
174
- }
125
+ export type ErrorCode = typeof ErrorCodes[keyof typeof ErrorCodes];