@facesmash/sdk 0.1.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/README.md +236 -0
- package/dist/index.cjs +658 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +192 -0
- package/dist/index.d.ts +192 -0
- package/dist/index.js +621 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +1068 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +292 -0
- package/dist/react.d.ts +292 -0
- package/dist/react.js +1024 -0
- package/dist/react.js.map +1 -0
- package/package.json +84 -0
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import PocketBase from 'pocketbase';
|
|
2
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
3
|
+
import React, { ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
/** Configuration for the FaceSmash client */
|
|
6
|
+
interface FaceSmashConfig {
|
|
7
|
+
/** PocketBase API URL (default: https://api.facesmash.app) */
|
|
8
|
+
apiUrl?: string;
|
|
9
|
+
/** URL to load face-api.js models from (default: jsdelivr CDN) */
|
|
10
|
+
modelUrl?: string;
|
|
11
|
+
/** Minimum confidence for SSD MobileNet face detection (default: 0.3) */
|
|
12
|
+
minDetectionConfidence?: number;
|
|
13
|
+
/** Similarity threshold for face matching (default: 0.45) */
|
|
14
|
+
matchThreshold?: number;
|
|
15
|
+
/** Minimum quality score to accept a face scan (default: 0.2) */
|
|
16
|
+
minQualityScore?: number;
|
|
17
|
+
/** Maximum face templates stored per user (default: 10) */
|
|
18
|
+
maxTemplatesPerUser?: number;
|
|
19
|
+
/** Enable debug logging (default: false) */
|
|
20
|
+
debug?: boolean;
|
|
21
|
+
}
|
|
22
|
+
/** Resolved config with all defaults applied */
|
|
23
|
+
interface ResolvedConfig {
|
|
24
|
+
apiUrl: string;
|
|
25
|
+
modelUrl: string;
|
|
26
|
+
minDetectionConfidence: number;
|
|
27
|
+
matchThreshold: number;
|
|
28
|
+
minQualityScore: number;
|
|
29
|
+
maxTemplatesPerUser: number;
|
|
30
|
+
debug: boolean;
|
|
31
|
+
}
|
|
32
|
+
/** Head pose estimation */
|
|
33
|
+
interface HeadPose {
|
|
34
|
+
yaw: number;
|
|
35
|
+
pitch: number;
|
|
36
|
+
roll: number;
|
|
37
|
+
isFrontal: boolean;
|
|
38
|
+
}
|
|
39
|
+
/** Face size validation result */
|
|
40
|
+
interface FaceSizeCheck {
|
|
41
|
+
isValid: boolean;
|
|
42
|
+
ratio: number;
|
|
43
|
+
reason?: string;
|
|
44
|
+
}
|
|
45
|
+
/** Lighting analysis */
|
|
46
|
+
interface LightingAnalysis {
|
|
47
|
+
score: number;
|
|
48
|
+
brightness: number;
|
|
49
|
+
contrast: number;
|
|
50
|
+
evenness: number;
|
|
51
|
+
conditions: {
|
|
52
|
+
tooDark: boolean;
|
|
53
|
+
tooBright: boolean;
|
|
54
|
+
uneven: boolean;
|
|
55
|
+
optimal: boolean;
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
/** Full face analysis result */
|
|
59
|
+
interface FaceAnalysis {
|
|
60
|
+
descriptor: Float32Array;
|
|
61
|
+
normalizedDescriptor: Float32Array;
|
|
62
|
+
confidence: number;
|
|
63
|
+
qualityScore: number;
|
|
64
|
+
lightingScore: number;
|
|
65
|
+
headPose: HeadPose;
|
|
66
|
+
faceSizeCheck: FaceSizeCheck;
|
|
67
|
+
eyeAspectRatio: number;
|
|
68
|
+
rejectionReason?: string;
|
|
69
|
+
}
|
|
70
|
+
/** Face match result */
|
|
71
|
+
interface MatchResult {
|
|
72
|
+
isMatch: boolean;
|
|
73
|
+
similarity: number;
|
|
74
|
+
adaptedThreshold: number;
|
|
75
|
+
}
|
|
76
|
+
/** Multi-template match result */
|
|
77
|
+
interface MultiTemplateMatchResult {
|
|
78
|
+
isMatch: boolean;
|
|
79
|
+
bestSimilarity: number;
|
|
80
|
+
avgSimilarity: number;
|
|
81
|
+
matchCount: number;
|
|
82
|
+
}
|
|
83
|
+
/** A stored face template */
|
|
84
|
+
interface FaceTemplate {
|
|
85
|
+
id: string;
|
|
86
|
+
user_email: string;
|
|
87
|
+
descriptor: number[];
|
|
88
|
+
quality_score: number;
|
|
89
|
+
created: string;
|
|
90
|
+
}
|
|
91
|
+
/** A user profile from PocketBase */
|
|
92
|
+
interface UserProfile {
|
|
93
|
+
id: string;
|
|
94
|
+
name: string;
|
|
95
|
+
email: string;
|
|
96
|
+
face_embedding: number[];
|
|
97
|
+
created: string;
|
|
98
|
+
updated: string;
|
|
99
|
+
}
|
|
100
|
+
/** Login result */
|
|
101
|
+
interface LoginResult {
|
|
102
|
+
success: boolean;
|
|
103
|
+
user?: UserProfile;
|
|
104
|
+
similarity?: number;
|
|
105
|
+
error?: string;
|
|
106
|
+
}
|
|
107
|
+
/** Registration result */
|
|
108
|
+
interface RegisterResult {
|
|
109
|
+
success: boolean;
|
|
110
|
+
user?: UserProfile;
|
|
111
|
+
error?: string;
|
|
112
|
+
}
|
|
113
|
+
/** Model loading progress callback */
|
|
114
|
+
type OnProgress = (progress: number) => void;
|
|
115
|
+
/** Event types emitted by the SDK */
|
|
116
|
+
type FaceSmashEvent = {
|
|
117
|
+
type: 'models-loading';
|
|
118
|
+
progress: number;
|
|
119
|
+
} | {
|
|
120
|
+
type: 'models-loaded';
|
|
121
|
+
} | {
|
|
122
|
+
type: 'models-error';
|
|
123
|
+
error: string;
|
|
124
|
+
} | {
|
|
125
|
+
type: 'face-detected';
|
|
126
|
+
analysis: FaceAnalysis;
|
|
127
|
+
} | {
|
|
128
|
+
type: 'face-lost';
|
|
129
|
+
} | {
|
|
130
|
+
type: 'login-start';
|
|
131
|
+
} | {
|
|
132
|
+
type: 'login-success';
|
|
133
|
+
user: UserProfile;
|
|
134
|
+
similarity: number;
|
|
135
|
+
} | {
|
|
136
|
+
type: 'login-failed';
|
|
137
|
+
error: string;
|
|
138
|
+
bestSimilarity?: number;
|
|
139
|
+
} | {
|
|
140
|
+
type: 'register-start';
|
|
141
|
+
} | {
|
|
142
|
+
type: 'register-success';
|
|
143
|
+
user: UserProfile;
|
|
144
|
+
} | {
|
|
145
|
+
type: 'register-failed';
|
|
146
|
+
error: string;
|
|
147
|
+
};
|
|
148
|
+
type FaceSmashEventListener = (event: FaceSmashEvent) => void;
|
|
149
|
+
|
|
150
|
+
declare class FaceSmashClient {
|
|
151
|
+
readonly config: ResolvedConfig;
|
|
152
|
+
readonly pb: PocketBase;
|
|
153
|
+
private listeners;
|
|
154
|
+
private _modelsLoaded;
|
|
155
|
+
constructor(config?: FaceSmashConfig);
|
|
156
|
+
on(listener: FaceSmashEventListener): () => void;
|
|
157
|
+
private emit;
|
|
158
|
+
get isReady(): boolean;
|
|
159
|
+
init(onProgress?: OnProgress): Promise<boolean>;
|
|
160
|
+
analyzeFace(imageData: string): Promise<FaceAnalysis | null>;
|
|
161
|
+
login(images: string[]): Promise<LoginResult>;
|
|
162
|
+
register(name: string, images: string[], email?: string): Promise<RegisterResult>;
|
|
163
|
+
private ensureReady;
|
|
164
|
+
private storeLoginScan;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
declare function loadModels(config: ResolvedConfig, onProgress?: (progress: number) => void): Promise<boolean>;
|
|
168
|
+
declare function areModelsLoaded(): boolean;
|
|
169
|
+
declare function extractDescriptor(input: string | HTMLVideoElement | HTMLCanvasElement | HTMLImageElement, config: ResolvedConfig): Promise<Float32Array | null>;
|
|
170
|
+
declare function analyzeFace(imageData: string, config: ResolvedConfig): Promise<FaceAnalysis | null>;
|
|
171
|
+
declare function processImages(images: string[], config: ResolvedConfig): Promise<Float32Array | null>;
|
|
172
|
+
declare function normalizeDescriptor(descriptor: Float32Array): Float32Array;
|
|
173
|
+
|
|
174
|
+
/** Calculate cosine similarity between two face descriptors (1 - euclidean distance) */
|
|
175
|
+
declare function calculateSimilarity(d1: Float32Array, d2: Float32Array): number;
|
|
176
|
+
/** Check if two face descriptors match */
|
|
177
|
+
declare function facesMatch(d1: Float32Array, d2: Float32Array, threshold?: number): boolean;
|
|
178
|
+
/**
|
|
179
|
+
* Enhanced face matching with adaptive threshold.
|
|
180
|
+
* Adjusts threshold based on lighting conditions and user confidence boost.
|
|
181
|
+
*/
|
|
182
|
+
declare function enhancedMatch(descriptor1: Float32Array, descriptor2: Float32Array, baseThreshold?: number, confidenceBoost?: number, lightingScore?: number): MatchResult;
|
|
183
|
+
/** Match a face descriptor against multiple stored templates */
|
|
184
|
+
declare function multiTemplateMatch(newDescriptor: Float32Array, templates: {
|
|
185
|
+
descriptor: Float32Array;
|
|
186
|
+
quality: number;
|
|
187
|
+
weight: number;
|
|
188
|
+
}[], baseThreshold: number, lightingScore?: number): MultiTemplateMatchResult;
|
|
189
|
+
/** Calculate a learning weight based on scan quality */
|
|
190
|
+
declare function calculateLearningWeight(qualityScore: number, lightingScore: number, confidence: number): number;
|
|
191
|
+
|
|
192
|
+
declare function createFaceSmash(config?: FaceSmashConfig): FaceSmashClient;
|
|
193
|
+
|
|
194
|
+
interface FaceSmashContextValue {
|
|
195
|
+
client: FaceSmashClient;
|
|
196
|
+
isReady: boolean;
|
|
197
|
+
isLoading: boolean;
|
|
198
|
+
loadProgress: number;
|
|
199
|
+
error: string | null;
|
|
200
|
+
retryInit: () => void;
|
|
201
|
+
}
|
|
202
|
+
interface FaceSmashProviderProps {
|
|
203
|
+
children: ReactNode;
|
|
204
|
+
/** SDK configuration */
|
|
205
|
+
config?: FaceSmashConfig;
|
|
206
|
+
/** Called when models finish loading */
|
|
207
|
+
onReady?: () => void;
|
|
208
|
+
/** Called on model loading error */
|
|
209
|
+
onError?: (error: string) => void;
|
|
210
|
+
/** Called for any SDK event */
|
|
211
|
+
onEvent?: (event: FaceSmashEvent) => void;
|
|
212
|
+
}
|
|
213
|
+
declare function FaceSmashProvider({ children, config, onReady, onError, onEvent, }: FaceSmashProviderProps): react_jsx_runtime.JSX.Element;
|
|
214
|
+
declare function useFaceSmash(): FaceSmashContextValue;
|
|
215
|
+
|
|
216
|
+
interface FaceLoginProps {
|
|
217
|
+
/** Called with the login result when authentication completes */
|
|
218
|
+
onResult: (result: LoginResult) => void;
|
|
219
|
+
/** Number of images to capture for matching (default: 3) */
|
|
220
|
+
captureCount?: number;
|
|
221
|
+
/** Delay between captures in ms (default: 500) */
|
|
222
|
+
captureDelay?: number;
|
|
223
|
+
/** Auto-start scanning when component mounts (default: true) */
|
|
224
|
+
autoStart?: boolean;
|
|
225
|
+
/** Custom className for the container */
|
|
226
|
+
className?: string;
|
|
227
|
+
/** Custom overlay content rendered on top of the video */
|
|
228
|
+
overlay?: React.ReactNode;
|
|
229
|
+
/** Custom loading content */
|
|
230
|
+
loadingContent?: React.ReactNode;
|
|
231
|
+
/** Custom error content */
|
|
232
|
+
errorContent?: (error: string, retry: () => void) => React.ReactNode;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Drop-in face login component.
|
|
236
|
+
* Renders a webcam feed, auto-detects a face, captures images, and authenticates.
|
|
237
|
+
*/
|
|
238
|
+
declare function FaceLogin({ onResult, captureCount, captureDelay, autoStart, className, overlay, loadingContent, errorContent, }: FaceLoginProps): react_jsx_runtime.JSX.Element;
|
|
239
|
+
|
|
240
|
+
interface FaceRegisterProps {
|
|
241
|
+
/** User's display name */
|
|
242
|
+
name: string;
|
|
243
|
+
/** Optional email */
|
|
244
|
+
email?: string;
|
|
245
|
+
/** Called with the registration result */
|
|
246
|
+
onResult: (result: RegisterResult) => void;
|
|
247
|
+
/** Number of images to capture (default: 3) */
|
|
248
|
+
captureCount?: number;
|
|
249
|
+
/** Delay between captures in ms (default: 500) */
|
|
250
|
+
captureDelay?: number;
|
|
251
|
+
/** Auto-start when component mounts (default: true) */
|
|
252
|
+
autoStart?: boolean;
|
|
253
|
+
/** Custom className for the container */
|
|
254
|
+
className?: string;
|
|
255
|
+
/** Custom overlay */
|
|
256
|
+
overlay?: React.ReactNode;
|
|
257
|
+
/** Custom loading content */
|
|
258
|
+
loadingContent?: React.ReactNode;
|
|
259
|
+
/** Custom error content */
|
|
260
|
+
errorContent?: (error: string, retry: () => void) => React.ReactNode;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Drop-in face registration component.
|
|
264
|
+
* Renders a webcam feed, captures face images, and registers a new user.
|
|
265
|
+
*/
|
|
266
|
+
declare function FaceRegister({ name, email, onResult, captureCount, captureDelay, autoStart, className, overlay, loadingContent, errorContent, }: FaceRegisterProps): react_jsx_runtime.JSX.Element;
|
|
267
|
+
|
|
268
|
+
/** Hook for face login flow */
|
|
269
|
+
declare function useFaceLogin(): {
|
|
270
|
+
login: (images: string[]) => Promise<LoginResult>;
|
|
271
|
+
isScanning: boolean;
|
|
272
|
+
result: LoginResult | null;
|
|
273
|
+
reset: () => void;
|
|
274
|
+
isReady: boolean;
|
|
275
|
+
};
|
|
276
|
+
/** Hook for face registration flow */
|
|
277
|
+
declare function useFaceRegister(): {
|
|
278
|
+
register: (name: string, images: string[], email?: string) => Promise<RegisterResult>;
|
|
279
|
+
isRegistering: boolean;
|
|
280
|
+
result: RegisterResult | null;
|
|
281
|
+
reset: () => void;
|
|
282
|
+
isReady: boolean;
|
|
283
|
+
};
|
|
284
|
+
/** Hook for face analysis (quality scoring, detection) */
|
|
285
|
+
declare function useFaceAnalysis(): {
|
|
286
|
+
analyze: (imageData: string) => Promise<FaceAnalysis | null>;
|
|
287
|
+
analysis: FaceAnalysis | null;
|
|
288
|
+
isAnalyzing: boolean;
|
|
289
|
+
isReady: boolean;
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
export { type FaceAnalysis, FaceLogin, type FaceLoginProps, FaceRegister, type FaceRegisterProps, type FaceSizeCheck, FaceSmashClient, type FaceSmashConfig, type FaceSmashEvent, type FaceSmashEventListener, FaceSmashProvider, type FaceSmashProviderProps, type FaceTemplate, type HeadPose, type LightingAnalysis, type LoginResult, type MatchResult, type MultiTemplateMatchResult, type OnProgress, type RegisterResult, type ResolvedConfig, type UserProfile, analyzeFace, areModelsLoaded, calculateLearningWeight, calculateSimilarity, createFaceSmash, enhancedMatch, extractDescriptor, facesMatch, loadModels, multiTemplateMatch, normalizeDescriptor, processImages, useFaceAnalysis, useFaceLogin, useFaceRegister, useFaceSmash };
|