omnipay-reactnative-sdk 1.2.1 → 1.2.2-beta.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 (47) hide show
  1. package/android/build.gradle +13 -0
  2. package/android/src/main/AndroidManifest.xml +5 -0
  3. package/android/src/main/java/com/omniretail/omnipay/LivenessCameraViewManager.java +116 -0
  4. package/android/src/main/java/com/omniretail/omnipay/LivenessDetectionModule.java +588 -0
  5. package/android/src/main/java/com/omniretail/omnipay/OmnipayActivityPackage.java +4 -1
  6. package/ios/LivenessCameraView.h +22 -0
  7. package/ios/LivenessCameraView.m +135 -0
  8. package/ios/LivenessCameraViewManager.h +12 -0
  9. package/ios/LivenessCameraViewManager.m +24 -0
  10. package/ios/LivenessDetectionModule.h +46 -0
  11. package/ios/LivenessDetectionModule.m +603 -0
  12. package/lib/commonjs/components/OmnipayProvider.js +10 -1
  13. package/lib/commonjs/components/OmnipayProvider.js.map +1 -1
  14. package/lib/commonjs/components/biometrics/FaceVerification.js +439 -0
  15. package/lib/commonjs/components/biometrics/FaceVerification.js.map +1 -0
  16. package/lib/commonjs/components/biometrics/LivenessCameraView.js +43 -0
  17. package/lib/commonjs/components/biometrics/LivenessCameraView.js.map +1 -0
  18. package/lib/commonjs/components/biometrics/LivenessDetection.js +252 -0
  19. package/lib/commonjs/components/biometrics/LivenessDetection.js.map +1 -0
  20. package/lib/commonjs/index.js +28 -0
  21. package/lib/commonjs/index.js.map +1 -1
  22. package/lib/module/components/OmnipayProvider.js +10 -1
  23. package/lib/module/components/OmnipayProvider.js.map +1 -1
  24. package/lib/module/components/biometrics/FaceVerification.js +429 -0
  25. package/lib/module/components/biometrics/FaceVerification.js.map +1 -0
  26. package/lib/module/components/biometrics/LivenessCameraView.js +38 -0
  27. package/lib/module/components/biometrics/LivenessCameraView.js.map +1 -0
  28. package/lib/module/components/biometrics/LivenessDetection.js +244 -0
  29. package/lib/module/components/biometrics/LivenessDetection.js.map +1 -0
  30. package/lib/module/index.js +5 -0
  31. package/lib/module/index.js.map +1 -1
  32. package/lib/typescript/components/OmnipayProvider.d.ts.map +1 -1
  33. package/lib/typescript/components/biometrics/FaceVerification.d.ts +12 -0
  34. package/lib/typescript/components/biometrics/FaceVerification.d.ts.map +1 -0
  35. package/lib/typescript/components/biometrics/LivenessCameraView.d.ts +22 -0
  36. package/lib/typescript/components/biometrics/LivenessCameraView.d.ts.map +1 -0
  37. package/lib/typescript/components/biometrics/LivenessDetection.d.ts +73 -0
  38. package/lib/typescript/components/biometrics/LivenessDetection.d.ts.map +1 -0
  39. package/lib/typescript/index.d.ts +3 -0
  40. package/lib/typescript/index.d.ts.map +1 -1
  41. package/omnipay-reactnative-sdk.podspec +47 -0
  42. package/package.json +3 -2
  43. package/src/components/OmnipayProvider.tsx +12 -0
  44. package/src/components/biometrics/FaceVerification.tsx +484 -0
  45. package/src/components/biometrics/LivenessCameraView.tsx +61 -0
  46. package/src/components/biometrics/LivenessDetection.ts +305 -0
  47. package/src/index.tsx +18 -0
@@ -0,0 +1,305 @@
1
+ import { NativeModules, NativeEventEmitter } from 'react-native';
2
+
3
+ const { LivenessDetection: LivenessDetectionNative } = NativeModules;
4
+
5
+ // TypeScript interfaces matching PRD specifications
6
+ export interface LivenessDetectionConfig {
7
+ challenges: ('smile' | 'blink' | 'turn_left' | 'turn_right')[];
8
+ timeout?: number; // Optional timeout in milliseconds
9
+ }
10
+
11
+ export interface ChallengeResult {
12
+ challenge: string;
13
+ success: boolean;
14
+ timestamp: number;
15
+ duration?: number; // Time taken to complete challenge
16
+ }
17
+
18
+ export interface LivenessResult {
19
+ success: boolean;
20
+ screenshot?: string; // Base64 encoded image
21
+ challengeResults: ChallengeResult[];
22
+ error?: string;
23
+ }
24
+
25
+ // Event callback types
26
+ export interface LivenessCallbacks {
27
+ onChallengeStart?: (challenge: string) => void;
28
+ onChallengeSuccess?: (challenge: string) => void;
29
+ onChallengeFailure?: (challenge: string, reason: string) => void;
30
+ onAllChallengesComplete?: (result: LivenessResult) => void;
31
+ onScreenshotCaptured?: (screenshot: string) => void;
32
+ }
33
+
34
+ // Main LivenessDetection class
35
+ class LivenessDetectionManager {
36
+ private eventEmitter: NativeEventEmitter | null = null;
37
+ private listeners: any[] = [];
38
+ private callbacks: LivenessCallbacks = {};
39
+ private isActive = false;
40
+ private challengeResults: ChallengeResult[] = [];
41
+ private startTime: number = 0;
42
+
43
+ constructor() {
44
+ if (LivenessDetectionNative) {
45
+ this.eventEmitter = new NativeEventEmitter(LivenessDetectionNative);
46
+ this.setupEventListeners();
47
+ }
48
+ }
49
+
50
+ private setupEventListeners() {
51
+ if (!this.eventEmitter) return;
52
+
53
+ // Challenge start event
54
+ this.listeners.push(
55
+ this.eventEmitter.addListener('onChallengeStart', (event) => {
56
+ console.log('Liveness: Challenge started -', event.challenge);
57
+ if (this.callbacks.onChallengeStart) {
58
+ this.callbacks.onChallengeStart(event.challenge);
59
+ }
60
+ })
61
+ );
62
+
63
+ // Challenge success event
64
+ this.listeners.push(
65
+ this.eventEmitter.addListener('onChallengeSuccess', (event) => {
66
+ console.log('Liveness: Challenge completed -', event.challenge);
67
+
68
+ // Record challenge result
69
+ const result: ChallengeResult = {
70
+ challenge: event.challenge,
71
+ success: true,
72
+ timestamp: Date.now(),
73
+ duration: Date.now() - this.startTime,
74
+ };
75
+ this.challengeResults.push(result);
76
+
77
+ if (this.callbacks.onChallengeSuccess) {
78
+ this.callbacks.onChallengeSuccess(event.challenge);
79
+ }
80
+ })
81
+ );
82
+
83
+ // Challenge failure event
84
+ this.listeners.push(
85
+ this.eventEmitter.addListener('onChallengeFailure', (event) => {
86
+ console.log(
87
+ 'Liveness: Challenge failed -',
88
+ event.challenge,
89
+ event.reason
90
+ );
91
+
92
+ // Record failed challenge result
93
+ const result: ChallengeResult = {
94
+ challenge: event.challenge,
95
+ success: false,
96
+ timestamp: Date.now(),
97
+ duration: Date.now() - this.startTime,
98
+ };
99
+ this.challengeResults.push(result);
100
+
101
+ if (this.callbacks.onChallengeFailure) {
102
+ this.callbacks.onChallengeFailure(event.challenge, event.reason);
103
+ }
104
+ })
105
+ );
106
+
107
+ // All challenges complete event
108
+ this.listeners.push(
109
+ this.eventEmitter.addListener('onAllChallengesComplete', (event) => {
110
+ console.log('Liveness: All challenges completed', event);
111
+
112
+ const result: LivenessResult = {
113
+ success: event.success,
114
+ screenshot: event.screenshot,
115
+ challengeResults: this.challengeResults,
116
+ };
117
+
118
+ this.isActive = false;
119
+
120
+ if (this.callbacks.onAllChallengesComplete) {
121
+ this.callbacks.onAllChallengesComplete(result);
122
+ }
123
+ })
124
+ );
125
+
126
+ // Screenshot captured event
127
+ this.listeners.push(
128
+ this.eventEmitter.addListener('onScreenshotCaptured', (event) => {
129
+ console.log('Liveness: Screenshot captured');
130
+
131
+ if (this.callbacks.onScreenshotCaptured) {
132
+ this.callbacks.onScreenshotCaptured(event.screenshot);
133
+ }
134
+ })
135
+ );
136
+ }
137
+
138
+ /**
139
+ * Start liveness detection with specified challenges
140
+ * @param config - Configuration including challenges array
141
+ * @param callbacks - Event callbacks
142
+ * @returns Promise resolving to LivenessResult
143
+ */
144
+ async startLivenessDetection(
145
+ config: LivenessDetectionConfig,
146
+ callbacks?: LivenessCallbacks
147
+ ): Promise<LivenessResult> {
148
+ if (this.isActive) {
149
+ throw new Error('Liveness detection is already active');
150
+ }
151
+
152
+ if (!LivenessDetectionNative) {
153
+ throw new Error('Liveness detection is not available on this platform');
154
+ }
155
+
156
+ // Validate challenges
157
+ if (!config.challenges || config.challenges.length === 0) {
158
+ throw new Error('At least one challenge must be specified');
159
+ }
160
+
161
+ const validChallenges = ['smile', 'blink', 'turn_left', 'turn_right'];
162
+ for (const challenge of config.challenges) {
163
+ if (!validChallenges.includes(challenge)) {
164
+ throw new Error(`Invalid challenge: ${challenge}`);
165
+ }
166
+ }
167
+
168
+ try {
169
+ // Check camera permission first
170
+ const hasPermission = await this.checkCameraPermission();
171
+ if (!hasPermission) {
172
+ throw new Error(
173
+ 'Camera permission is required. Please call requestCameraPermission() first.'
174
+ );
175
+ }
176
+
177
+ // Set callbacks
178
+ this.callbacks = callbacks || {};
179
+ this.challengeResults = [];
180
+ this.startTime = Date.now();
181
+ this.isActive = true;
182
+
183
+ // Start detection on native side
184
+ const result = await LivenessDetectionNative.startLivenessDetection(
185
+ config.challenges
186
+ );
187
+ console.log('Liveness detection started:', result);
188
+
189
+ // Return a promise that resolves when all challenges are complete
190
+ return new Promise((resolve, reject) => {
191
+ const originalOnComplete = this.callbacks.onAllChallengesComplete;
192
+
193
+ this.callbacks.onAllChallengesComplete = (
194
+ livenessResult: LivenessResult
195
+ ) => {
196
+ // Call original callback if provided
197
+ if (originalOnComplete) {
198
+ originalOnComplete(livenessResult);
199
+ }
200
+
201
+ // Resolve the promise
202
+ resolve(livenessResult);
203
+ };
204
+
205
+ // Set up timeout if specified
206
+ if (config.timeout) {
207
+ setTimeout(() => {
208
+ if (this.isActive) {
209
+ this.stopDetection();
210
+ reject(new Error('Liveness detection timed out'));
211
+ }
212
+ }, config.timeout);
213
+ }
214
+ });
215
+ } catch (error) {
216
+ this.isActive = false;
217
+ throw error;
218
+ }
219
+ }
220
+
221
+ /**
222
+ * Stop liveness detection
223
+ */
224
+ stopDetection(): void {
225
+ if (LivenessDetectionNative && this.isActive) {
226
+ LivenessDetectionNative.stopLivenessDetection();
227
+ this.isActive = false;
228
+ this.callbacks = {};
229
+ this.challengeResults = [];
230
+ console.log('Liveness detection stopped');
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Check if liveness detection is currently active
236
+ */
237
+ isDetectionActive(): boolean {
238
+ return this.isActive;
239
+ }
240
+
241
+ /**
242
+ * Get available challenge types
243
+ */
244
+ getAvailableChallenges(): string[] {
245
+ return ['smile', 'blink', 'turn_left', 'turn_right'];
246
+ }
247
+
248
+ /**
249
+ * Check if camera permission is granted
250
+ */
251
+ async checkCameraPermission(): Promise<boolean> {
252
+ if (!LivenessDetectionNative) {
253
+ throw new Error('Liveness detection is not available on this platform');
254
+ }
255
+
256
+ try {
257
+ return await LivenessDetectionNative.checkCameraPermission();
258
+ } catch (error) {
259
+ console.error('Failed to check camera permission:', error);
260
+ return false;
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Request camera permission from the user
266
+ */
267
+ async requestCameraPermission(): Promise<boolean> {
268
+ if (!LivenessDetectionNative) {
269
+ throw new Error('Liveness detection is not available on this platform');
270
+ }
271
+
272
+ try {
273
+ return await LivenessDetectionNative.requestCameraPermission();
274
+ } catch (error) {
275
+ console.error('Failed to request camera permission:', error);
276
+ return false;
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Cleanup - remove all event listeners
282
+ */
283
+ cleanup(): void {
284
+ this.listeners.forEach((listener) => {
285
+ if (listener && listener.remove) {
286
+ listener.remove();
287
+ }
288
+ });
289
+ this.listeners = [];
290
+ this.stopDetection();
291
+ }
292
+ }
293
+
294
+ // Export singleton instance
295
+ export const LivenessDetection = new LivenessDetectionManager();
296
+
297
+ // Types are already exported above
298
+
299
+ // Constants from native module
300
+ export const LivenessConstants = {
301
+ CHALLENGE_SMILE: 'smile',
302
+ CHALLENGE_BLINK: 'blink',
303
+ CHALLENGE_TURN_LEFT: 'turn_left',
304
+ CHALLENGE_TURN_RIGHT: 'turn_right',
305
+ } as const;
package/src/index.tsx CHANGED
@@ -2,4 +2,22 @@ import Omnipay from './components/OmnipayView';
2
2
 
3
3
  export { OmnipayProvider } from './components/OmnipayProvider';
4
4
  export { useOmnipay } from './hooks/useOmnipay';
5
+
6
+ // Liveness Detection exports
7
+ export {
8
+ LivenessDetection,
9
+ LivenessConstants,
10
+ type LivenessDetectionConfig,
11
+ type ChallengeResult,
12
+ type LivenessResult,
13
+ type LivenessCallbacks,
14
+ } from './components/biometrics/LivenessDetection';
15
+
16
+ export {
17
+ default as LivenessCameraView,
18
+ type LivenessCameraViewProps,
19
+ } from './components/biometrics/LivenessCameraView';
20
+
21
+ export { default as FaceVerification } from './components/biometrics/FaceVerification';
22
+
5
23
  export default Omnipay;