@myazahq/kyc-sdk-react-native 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/KycSdkReactNative.podspec +32 -0
- package/LICENSE +21 -0
- package/README.md +164 -0
- package/android/CMakeLists.txt +29 -0
- package/android/build.gradle +110 -0
- package/android/src/main/AndroidManifest.xml +12 -0
- package/android/src/main/cpp/cpp-adapter.cpp +12 -0
- package/android/src/main/java/co/myazahq/kyc/rn/MyazaFaceDetectorPackage.kt +36 -0
- package/android/src/main/java/co/myazahq/kyc/rn/MyazaStatusBarModule.kt +64 -0
- package/android/src/main/java/com/margelo/nitro/myazakyc/HybridMyazaFaceDetector.kt +134 -0
- package/app.plugin.js +55 -0
- package/expo-module.config.json +6 -0
- package/ios/HybridMyazaFaceDetector.swift +233 -0
- package/package.json +84 -0
- package/react-native.config.js +23 -0
- package/src/MyazaKYC.tsx +235 -0
- package/src/__tests__/cardCrop.test.ts +39 -0
- package/src/__tests__/deviceMetadata.test.ts +34 -0
- package/src/__tests__/errors.test.ts +34 -0
- package/src/__tests__/flow.test.ts +61 -0
- package/src/__tests__/gestureDetector.test.ts +37 -0
- package/src/__tests__/liveness.test.ts +112 -0
- package/src/__tests__/resolveUrl.test.ts +64 -0
- package/src/__tests__/validators.test.ts +38 -0
- package/src/assets/liveness/Blink.gif +0 -0
- package/src/assets/liveness/Nod.gif +0 -0
- package/src/assets/liveness/Smile.gif +0 -0
- package/src/assets/liveness/Turn.gif +0 -0
- package/src/components/CameraPermissionView.tsx +116 -0
- package/src/components/CameraViewfinder.tsx +156 -0
- package/src/components/CountryFlag.tsx +52 -0
- package/src/components/DocumentCropper.tsx +325 -0
- package/src/components/GlassIconButton.tsx +92 -0
- package/src/components/Icon.tsx +125 -0
- package/src/components/KycFlow.tsx +205 -0
- package/src/components/KycSheet.tsx +224 -0
- package/src/components/MyazaAlert.tsx +57 -0
- package/src/components/MyazaButton.tsx +101 -0
- package/src/components/MyazaCard.tsx +48 -0
- package/src/components/MyazaInput.tsx +112 -0
- package/src/components/MyazaPulseLoader.tsx +71 -0
- package/src/components/StatusBarController.tsx +42 -0
- package/src/components/StepHeader.tsx +56 -0
- package/src/components/StepIndicator.tsx +74 -0
- package/src/components/Typography.tsx +69 -0
- package/src/components/fonts.ts +49 -0
- package/src/components/glass/GlassGroup.tsx +34 -0
- package/src/components/glass/GlassSurface.tsx +64 -0
- package/src/components/runtime.tsx +93 -0
- package/src/components/toast.tsx +154 -0
- package/src/components/useBranding.ts +27 -0
- package/src/components/useVideoRecorder.ts +122 -0
- package/src/config/captureSettings.ts +67 -0
- package/src/config/idTypes.ts +79 -0
- package/src/config/theme.ts +186 -0
- package/src/index.ts +54 -0
- package/src/liveness/challengeManager.ts +130 -0
- package/src/liveness/faceDetector.ts +79 -0
- package/src/liveness/gestureDetector.ts +80 -0
- package/src/liveness/speech.ts +66 -0
- package/src/liveness/types.ts +99 -0
- package/src/liveness/useLiveness.ts +484 -0
- package/src/liveness/visionCameraFaceDetector.ts +118 -0
- package/src/screens/ConsentStep.tsx +164 -0
- package/src/screens/DocumentCaptureStep.tsx +500 -0
- package/src/screens/IdInputStep.tsx +79 -0
- package/src/screens/IdTypeStep.tsx +142 -0
- package/src/screens/LivenessAvatar.tsx +69 -0
- package/src/screens/LivenessStep.tsx +615 -0
- package/src/screens/SubmittedStep.tsx +177 -0
- package/src/services/api.ts +291 -0
- package/src/services/cardCrop.ts +52 -0
- package/src/services/deviceMetadata.ts +185 -0
- package/src/services/errors.ts +92 -0
- package/src/services/mediaCompress.ts +129 -0
- package/src/services/resolveUrl.ts +98 -0
- package/src/services/retry.ts +70 -0
- package/src/services/validators.ts +103 -0
- package/src/specs/MyazaFaceDetector.nitro.ts +44 -0
- package/src/store/kycStore.ts +288 -0
- package/src/store/serverConfig.ts +78 -0
- package/src/types/config.ts +239 -0
- package/src/types/country-flag-icons.d.ts +6 -0
- package/src/types/verification.ts +79 -0
- package/src/utils/platform.ts +23 -0
- package/src/utils/tokens.ts +10 -0
- package/src/utils/uuid.ts +31 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Submission callback payload (returned to onSubmit)
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
export interface KYCSubmission {
|
|
6
|
+
verificationId: string;
|
|
7
|
+
status: 'pending';
|
|
8
|
+
metadata: Record<string, string>;
|
|
9
|
+
submittedAt: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Technical error types (onError callback)
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Typed, documented technical-error categories surfaced through `onError`.
|
|
18
|
+
* These are IDENTICAL to the web + Flutter SDKs' codes so integrators get one
|
|
19
|
+
* consistent contract across all three platforms.
|
|
20
|
+
*
|
|
21
|
+
* - `network_error` — connection failure / timeout (after retries)
|
|
22
|
+
* - `invalid_api_key` — server returned 401
|
|
23
|
+
* - `insufficient_credits` — server returned 402 (see `details`)
|
|
24
|
+
* - `upload_failed` — `POST /api/kyc/upload` failed (after retries)
|
|
25
|
+
* - `camera_permission_denied` — the user denied (or the OS blocks) camera
|
|
26
|
+
* access; capture cannot proceed
|
|
27
|
+
* - `feature_disabled` — server returned 403 (ID type or a verification
|
|
28
|
+
* feature is not enabled for the org)
|
|
29
|
+
* - `unknown` — anything else
|
|
30
|
+
*
|
|
31
|
+
* > Voice guidance is text-to-speech *output* — it never records audio, so
|
|
32
|
+
* > there is no microphone-permission error code.
|
|
33
|
+
*/
|
|
34
|
+
export type KYCErrorCode =
|
|
35
|
+
| 'network_error'
|
|
36
|
+
| 'invalid_api_key'
|
|
37
|
+
| 'insufficient_credits'
|
|
38
|
+
| 'upload_failed'
|
|
39
|
+
| 'camera_permission_denied'
|
|
40
|
+
| 'feature_disabled'
|
|
41
|
+
| 'unknown';
|
|
42
|
+
|
|
43
|
+
export interface KYCErrorDetails {
|
|
44
|
+
required?: number;
|
|
45
|
+
balance?: number;
|
|
46
|
+
currency?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The error instance passed to `onError`. It is a real `Error` (so existing
|
|
51
|
+
* `onError: (error: Error) => void` handlers keep working) that additionally
|
|
52
|
+
* carries a typed `code` and optional `details`. Narrow with `instanceof
|
|
53
|
+
* KYCError` (or read `error.code`) to branch on the category.
|
|
54
|
+
*/
|
|
55
|
+
export class KYCError extends Error {
|
|
56
|
+
readonly code: KYCErrorCode;
|
|
57
|
+
readonly details?: KYCErrorDetails;
|
|
58
|
+
|
|
59
|
+
constructor(code: KYCErrorCode, message: string, details?: KYCErrorDetails) {
|
|
60
|
+
super(message);
|
|
61
|
+
this.name = 'KYCError';
|
|
62
|
+
this.code = code;
|
|
63
|
+
this.details = details;
|
|
64
|
+
// Restore the prototype chain for `instanceof` after transpilation.
|
|
65
|
+
Object.setPrototypeOf(this, KYCError.prototype);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
// API call status (used by stores)
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
|
|
73
|
+
export type ApiStatus = 'idle' | 'loading' | 'success' | 'error';
|
|
74
|
+
|
|
75
|
+
export interface ApiError {
|
|
76
|
+
message: string;
|
|
77
|
+
code?: string;
|
|
78
|
+
statusCode?: number;
|
|
79
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Thin wrapper around React Native's `Platform` so the SDK's pure-logic modules
|
|
2
|
+
// (resolveUrl, deviceMetadata) stay testable under a plain Node test runner —
|
|
3
|
+
// where the `react-native` module isn't resolvable. Under Metro/RN this reads
|
|
4
|
+
// the real `Platform.OS`; under Node it falls back to `'ios'`.
|
|
5
|
+
//
|
|
6
|
+
// This is the ONLY place the SDK reaches for `Platform` outside of React
|
|
7
|
+
// components, so the platform concern is isolated to a single file.
|
|
8
|
+
|
|
9
|
+
export type PlatformOS = 'ios' | 'android' | 'windows' | 'macos' | 'web';
|
|
10
|
+
|
|
11
|
+
function readOS(): PlatformOS {
|
|
12
|
+
try {
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
14
|
+
const rn = require('react-native') as { Platform?: { OS?: PlatformOS } };
|
|
15
|
+
return rn?.Platform?.OS ?? 'ios';
|
|
16
|
+
} catch {
|
|
17
|
+
return 'ios';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const OS: PlatformOS = readOS();
|
|
22
|
+
export const isAndroid = OS === 'android';
|
|
23
|
+
export const isIOS = OS === 'ios';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MyazaKYCConfig } from '../types/config';
|
|
2
|
+
|
|
3
|
+
// Replaces {firstName} / {lastName} tokens with values from userData (or ''),
|
|
4
|
+
// mirroring the Flutter SDK's `_fillTokens` and the web SDK's token handling.
|
|
5
|
+
export function fillTokens(template: string, userData: MyazaKYCConfig['userData']): string {
|
|
6
|
+
return template
|
|
7
|
+
.replace(/\{firstName\}/g, userData?.firstName ?? '')
|
|
8
|
+
.replace(/\{lastName\}/g, userData?.lastName ?? '')
|
|
9
|
+
.trim();
|
|
10
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Best-effort UUID/request-id generator. Prefers `expo-crypto`'s native
|
|
2
|
+
// randomUUID when available, falling back to a Math.random()-based v4 (good
|
|
3
|
+
// enough for a request correlation id — not used for anything security-sensitive).
|
|
4
|
+
|
|
5
|
+
interface ExpoCryptoModule {
|
|
6
|
+
randomUUID?: () => string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function fallbackUuid(): string {
|
|
10
|
+
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
|
11
|
+
const r = (Math.random() * 16) | 0;
|
|
12
|
+
const v = c === 'x' ? r : (r & 0x3) | 0x8;
|
|
13
|
+
return v.toString(16);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function uuid(): string {
|
|
18
|
+
try {
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
20
|
+
const crypto = require('expo-crypto') as ExpoCryptoModule;
|
|
21
|
+
if (crypto?.randomUUID) return crypto.randomUUID();
|
|
22
|
+
} catch {
|
|
23
|
+
/* expo-crypto not installed — fall through */
|
|
24
|
+
}
|
|
25
|
+
return fallbackUuid();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Prefixed request id sent as `metadata.requestId` on every verify. */
|
|
29
|
+
export function generateRequestId(): string {
|
|
30
|
+
return `kyc_${uuid()}`;
|
|
31
|
+
}
|