@kwik-id/sdk-react-native 0.0.0-stage → 0.1.0-alpha.1
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/LICENSE +22 -0
- package/README.md +312 -2
- package/app.plugin.js +40 -0
- package/lib/commonjs/api/api-client.js +213 -0
- package/lib/commonjs/api/api-client.js.map +1 -0
- package/lib/commonjs/api/api-error.js +29 -0
- package/lib/commonjs/api/api-error.js.map +1 -0
- package/lib/commonjs/api/index.js +33 -0
- package/lib/commonjs/api/index.js.map +1 -0
- package/lib/commonjs/api/upload.js +74 -0
- package/lib/commonjs/api/upload.js.map +1 -0
- package/lib/commonjs/camera/camera-view.js +227 -0
- package/lib/commonjs/camera/camera-view.js.map +1 -0
- package/lib/commonjs/camera/index.js +20 -0
- package/lib/commonjs/camera/index.js.map +1 -0
- package/lib/commonjs/camera/photo-capture.js +50 -0
- package/lib/commonjs/camera/photo-capture.js.map +1 -0
- package/lib/commonjs/crypto/fingerprint.js +43 -0
- package/lib/commonjs/crypto/fingerprint.js.map +1 -0
- package/lib/commonjs/crypto/hmac.js +150 -0
- package/lib/commonjs/crypto/hmac.js.map +1 -0
- package/lib/commonjs/crypto/index.js +39 -0
- package/lib/commonjs/crypto/index.js.map +1 -0
- package/lib/commonjs/crypto/session-manager.js +173 -0
- package/lib/commonjs/crypto/session-manager.js.map +1 -0
- package/lib/commonjs/i18n/en.js +297 -0
- package/lib/commonjs/i18n/en.js.map +1 -0
- package/lib/commonjs/i18n/fr.js +294 -0
- package/lib/commonjs/i18n/fr.js.map +1 -0
- package/lib/commonjs/i18n/index.js +34 -0
- package/lib/commonjs/i18n/index.js.map +1 -0
- package/lib/commonjs/i18n/locale.js +20 -0
- package/lib/commonjs/i18n/locale.js.map +1 -0
- package/lib/commonjs/i18n/translator.js +37 -0
- package/lib/commonjs/i18n/translator.js.map +1 -0
- package/lib/commonjs/index.js +187 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/lib/device-detector.js +34 -0
- package/lib/commonjs/lib/device-detector.js.map +1 -0
- package/lib/commonjs/lib/event-emitter.js +85 -0
- package/lib/commonjs/lib/event-emitter.js.map +1 -0
- package/lib/commonjs/lib/index.js +63 -0
- package/lib/commonjs/lib/index.js.map +1 -0
- package/lib/commonjs/lib/kwik-id-rn-sdk.js +156 -0
- package/lib/commonjs/lib/kwik-id-rn-sdk.js.map +1 -0
- package/lib/commonjs/lib/verification-machine.js +276 -0
- package/lib/commonjs/lib/verification-machine.js.map +1 -0
- package/lib/commonjs/package.json +1 -0
- package/lib/commonjs/types/events.js +6 -0
- package/lib/commonjs/types/events.js.map +1 -0
- package/lib/commonjs/types/index.js +2 -0
- package/lib/commonjs/types/index.js.map +1 -0
- package/lib/commonjs/ui/components/KwikIDVerificationModal.js +407 -0
- package/lib/commonjs/ui/components/KwikIDVerificationModal.js.map +1 -0
- package/lib/commonjs/ui/components/screens.js +338 -0
- package/lib/commonjs/ui/components/screens.js.map +1 -0
- package/lib/commonjs/ui/context/kwik-id-provider.js +52 -0
- package/lib/commonjs/ui/context/kwik-id-provider.js.map +1 -0
- package/lib/commonjs/ui/hooks/use-kwik-verification.js +77 -0
- package/lib/commonjs/ui/hooks/use-kwik-verification.js.map +1 -0
- package/lib/commonjs/ui/index.js +33 -0
- package/lib/commonjs/ui/index.js.map +1 -0
- package/lib/module/api/api-client.js +208 -0
- package/lib/module/api/api-client.js.map +1 -0
- package/lib/module/api/api-error.js +24 -0
- package/lib/module/api/api-error.js.map +1 -0
- package/lib/module/api/index.js +6 -0
- package/lib/module/api/index.js.map +1 -0
- package/lib/module/api/upload.js +68 -0
- package/lib/module/api/upload.js.map +1 -0
- package/lib/module/camera/camera-view.js +222 -0
- package/lib/module/camera/camera-view.js.map +1 -0
- package/lib/module/camera/index.js +5 -0
- package/lib/module/camera/index.js.map +1 -0
- package/lib/module/camera/photo-capture.js +45 -0
- package/lib/module/camera/photo-capture.js.map +1 -0
- package/lib/module/crypto/fingerprint.js +37 -0
- package/lib/module/crypto/fingerprint.js.map +1 -0
- package/lib/module/crypto/hmac.js +143 -0
- package/lib/module/crypto/hmac.js.map +1 -0
- package/lib/module/crypto/index.js +6 -0
- package/lib/module/crypto/index.js.map +1 -0
- package/lib/module/crypto/session-manager.js +169 -0
- package/lib/module/crypto/session-manager.js.map +1 -0
- package/lib/module/i18n/en.js +293 -0
- package/lib/module/i18n/en.js.map +1 -0
- package/lib/module/i18n/fr.js +290 -0
- package/lib/module/i18n/fr.js.map +1 -0
- package/lib/module/i18n/index.js +11 -0
- package/lib/module/i18n/index.js.map +1 -0
- package/lib/module/i18n/locale.js +15 -0
- package/lib/module/i18n/locale.js.map +1 -0
- package/lib/module/i18n/translator.js +34 -0
- package/lib/module/i18n/translator.js.map +1 -0
- package/lib/module/index.js +30 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/lib/device-detector.js +26 -0
- package/lib/module/lib/device-detector.js.map +1 -0
- package/lib/module/lib/event-emitter.js +80 -0
- package/lib/module/lib/event-emitter.js.map +1 -0
- package/lib/module/lib/index.js +6 -0
- package/lib/module/lib/index.js.map +1 -0
- package/lib/module/lib/kwik-id-rn-sdk.js +150 -0
- package/lib/module/lib/kwik-id-rn-sdk.js.map +1 -0
- package/lib/module/lib/verification-machine.js +268 -0
- package/lib/module/lib/verification-machine.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types/events.js +4 -0
- package/lib/module/types/events.js.map +1 -0
- package/lib/module/types/index.js +2 -0
- package/lib/module/types/index.js.map +1 -0
- package/lib/module/ui/components/KwikIDVerificationModal.js +402 -0
- package/lib/module/ui/components/KwikIDVerificationModal.js.map +1 -0
- package/lib/module/ui/components/screens.js +328 -0
- package/lib/module/ui/components/screens.js.map +1 -0
- package/lib/module/ui/context/kwik-id-provider.js +46 -0
- package/lib/module/ui/context/kwik-id-provider.js.map +1 -0
- package/lib/module/ui/hooks/use-kwik-verification.js +72 -0
- package/lib/module/ui/hooks/use-kwik-verification.js.map +1 -0
- package/lib/module/ui/index.js +6 -0
- package/lib/module/ui/index.js.map +1 -0
- package/lib/typescript/commonjs/api/api-client.d.ts +82 -0
- package/lib/typescript/commonjs/api/api-client.d.ts.map +1 -0
- package/lib/typescript/commonjs/api/api-error.d.ts +13 -0
- package/lib/typescript/commonjs/api/api-error.d.ts.map +1 -0
- package/lib/typescript/commonjs/api/index.d.ts +6 -0
- package/lib/typescript/commonjs/api/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/api/upload.d.ts +19 -0
- package/lib/typescript/commonjs/api/upload.d.ts.map +1 -0
- package/lib/typescript/commonjs/camera/camera-view.d.ts +25 -0
- package/lib/typescript/commonjs/camera/camera-view.d.ts.map +1 -0
- package/lib/typescript/commonjs/camera/index.d.ts +5 -0
- package/lib/typescript/commonjs/camera/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/camera/photo-capture.d.ts +9 -0
- package/lib/typescript/commonjs/camera/photo-capture.d.ts.map +1 -0
- package/lib/typescript/commonjs/crypto/fingerprint.d.ts +3 -0
- package/lib/typescript/commonjs/crypto/fingerprint.d.ts.map +1 -0
- package/lib/typescript/commonjs/crypto/hmac.d.ts +18 -0
- package/lib/typescript/commonjs/crypto/hmac.d.ts.map +1 -0
- package/lib/typescript/commonjs/crypto/index.d.ts +4 -0
- package/lib/typescript/commonjs/crypto/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/crypto/session-manager.d.ts +27 -0
- package/lib/typescript/commonjs/crypto/session-manager.d.ts.map +1 -0
- package/lib/typescript/commonjs/i18n/en.d.ts +291 -0
- package/lib/typescript/commonjs/i18n/en.d.ts.map +1 -0
- package/lib/typescript/commonjs/i18n/fr.d.ts +6 -0
- package/lib/typescript/commonjs/i18n/fr.d.ts.map +1 -0
- package/lib/typescript/commonjs/i18n/index.d.ts +10 -0
- package/lib/typescript/commonjs/i18n/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/i18n/locale.d.ts +4 -0
- package/lib/typescript/commonjs/i18n/locale.d.ts.map +1 -0
- package/lib/typescript/commonjs/i18n/translator.d.ts +15 -0
- package/lib/typescript/commonjs/i18n/translator.d.ts.map +1 -0
- package/lib/typescript/commonjs/index.d.ts +24 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/device-detector.d.ts +5 -0
- package/lib/typescript/commonjs/lib/device-detector.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/event-emitter.d.ts +19 -0
- package/lib/typescript/commonjs/lib/event-emitter.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/index.d.ts +5 -0
- package/lib/typescript/commonjs/lib/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/kwik-id-rn-sdk.d.ts +43 -0
- package/lib/typescript/commonjs/lib/kwik-id-rn-sdk.d.ts.map +1 -0
- package/lib/typescript/commonjs/lib/verification-machine.d.ts +78 -0
- package/lib/typescript/commonjs/lib/verification-machine.d.ts.map +1 -0
- package/lib/typescript/commonjs/package.json +1 -0
- package/lib/typescript/commonjs/types/events.d.ts +94 -0
- package/lib/typescript/commonjs/types/events.d.ts.map +1 -0
- package/lib/typescript/commonjs/types/index.d.ts +242 -0
- package/lib/typescript/commonjs/types/index.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/KwikIDVerificationModal.d.ts +21 -0
- package/lib/typescript/commonjs/ui/components/KwikIDVerificationModal.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/components/screens.d.ts +46 -0
- package/lib/typescript/commonjs/ui/components/screens.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/context/kwik-id-provider.d.ts +19 -0
- package/lib/typescript/commonjs/ui/context/kwik-id-provider.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/hooks/use-kwik-verification.d.ts +29 -0
- package/lib/typescript/commonjs/ui/hooks/use-kwik-verification.d.ts.map +1 -0
- package/lib/typescript/commonjs/ui/index.d.ts +7 -0
- package/lib/typescript/commonjs/ui/index.d.ts.map +1 -0
- package/lib/typescript/module/api/api-client.d.ts +82 -0
- package/lib/typescript/module/api/api-client.d.ts.map +1 -0
- package/lib/typescript/module/api/api-error.d.ts +13 -0
- package/lib/typescript/module/api/api-error.d.ts.map +1 -0
- package/lib/typescript/module/api/index.d.ts +6 -0
- package/lib/typescript/module/api/index.d.ts.map +1 -0
- package/lib/typescript/module/api/upload.d.ts +19 -0
- package/lib/typescript/module/api/upload.d.ts.map +1 -0
- package/lib/typescript/module/camera/camera-view.d.ts +25 -0
- package/lib/typescript/module/camera/camera-view.d.ts.map +1 -0
- package/lib/typescript/module/camera/index.d.ts +5 -0
- package/lib/typescript/module/camera/index.d.ts.map +1 -0
- package/lib/typescript/module/camera/photo-capture.d.ts +9 -0
- package/lib/typescript/module/camera/photo-capture.d.ts.map +1 -0
- package/lib/typescript/module/crypto/fingerprint.d.ts +3 -0
- package/lib/typescript/module/crypto/fingerprint.d.ts.map +1 -0
- package/lib/typescript/module/crypto/hmac.d.ts +18 -0
- package/lib/typescript/module/crypto/hmac.d.ts.map +1 -0
- package/lib/typescript/module/crypto/index.d.ts +4 -0
- package/lib/typescript/module/crypto/index.d.ts.map +1 -0
- package/lib/typescript/module/crypto/session-manager.d.ts +27 -0
- package/lib/typescript/module/crypto/session-manager.d.ts.map +1 -0
- package/lib/typescript/module/i18n/en.d.ts +291 -0
- package/lib/typescript/module/i18n/en.d.ts.map +1 -0
- package/lib/typescript/module/i18n/fr.d.ts +6 -0
- package/lib/typescript/module/i18n/fr.d.ts.map +1 -0
- package/lib/typescript/module/i18n/index.d.ts +10 -0
- package/lib/typescript/module/i18n/index.d.ts.map +1 -0
- package/lib/typescript/module/i18n/locale.d.ts +4 -0
- package/lib/typescript/module/i18n/locale.d.ts.map +1 -0
- package/lib/typescript/module/i18n/translator.d.ts +15 -0
- package/lib/typescript/module/i18n/translator.d.ts.map +1 -0
- package/lib/typescript/module/index.d.ts +24 -0
- package/lib/typescript/module/index.d.ts.map +1 -0
- package/lib/typescript/module/lib/device-detector.d.ts +5 -0
- package/lib/typescript/module/lib/device-detector.d.ts.map +1 -0
- package/lib/typescript/module/lib/event-emitter.d.ts +19 -0
- package/lib/typescript/module/lib/event-emitter.d.ts.map +1 -0
- package/lib/typescript/module/lib/index.d.ts +5 -0
- package/lib/typescript/module/lib/index.d.ts.map +1 -0
- package/lib/typescript/module/lib/kwik-id-rn-sdk.d.ts +43 -0
- package/lib/typescript/module/lib/kwik-id-rn-sdk.d.ts.map +1 -0
- package/lib/typescript/module/lib/verification-machine.d.ts +78 -0
- package/lib/typescript/module/lib/verification-machine.d.ts.map +1 -0
- package/lib/typescript/module/package.json +1 -0
- package/lib/typescript/module/types/events.d.ts +94 -0
- package/lib/typescript/module/types/events.d.ts.map +1 -0
- package/lib/typescript/module/types/index.d.ts +242 -0
- package/lib/typescript/module/types/index.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/KwikIDVerificationModal.d.ts +21 -0
- package/lib/typescript/module/ui/components/KwikIDVerificationModal.d.ts.map +1 -0
- package/lib/typescript/module/ui/components/screens.d.ts +46 -0
- package/lib/typescript/module/ui/components/screens.d.ts.map +1 -0
- package/lib/typescript/module/ui/context/kwik-id-provider.d.ts +19 -0
- package/lib/typescript/module/ui/context/kwik-id-provider.d.ts.map +1 -0
- package/lib/typescript/module/ui/hooks/use-kwik-verification.d.ts +29 -0
- package/lib/typescript/module/ui/hooks/use-kwik-verification.d.ts.map +1 -0
- package/lib/typescript/module/ui/index.d.ts +7 -0
- package/lib/typescript/module/ui/index.d.ts.map +1 -0
- package/package.json +121 -3
- package/src/api/api-client.ts +319 -0
- package/src/api/api-error.ts +28 -0
- package/src/api/index.ts +12 -0
- package/src/api/upload.ts +87 -0
- package/src/camera/camera-view.tsx +217 -0
- package/src/camera/index.ts +4 -0
- package/src/camera/photo-capture.ts +58 -0
- package/src/crypto/fingerprint.ts +46 -0
- package/src/crypto/hmac.ts +172 -0
- package/src/crypto/index.ts +3 -0
- package/src/crypto/session-manager.ts +200 -0
- package/src/i18n/en.ts +315 -0
- package/src/i18n/fr.ts +325 -0
- package/src/i18n/index.ts +9 -0
- package/src/i18n/locale.ts +15 -0
- package/src/i18n/translator.ts +37 -0
- package/src/index.ts +102 -0
- package/src/lib/device-detector.ts +32 -0
- package/src/lib/event-emitter.ts +90 -0
- package/src/lib/index.ts +15 -0
- package/src/lib/kwik-id-rn-sdk.ts +160 -0
- package/src/lib/verification-machine.ts +273 -0
- package/src/types/events.ts +75 -0
- package/src/types/index.ts +309 -0
- package/src/ui/components/KwikIDVerificationModal.tsx +450 -0
- package/src/ui/components/screens.tsx +283 -0
- package/src/ui/context/kwik-id-provider.tsx +72 -0
- package/src/ui/hooks/use-kwik-verification.ts +121 -0
- package/src/ui/index.ts +9 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2026 Kwik Nkap Technologies. All rights reserved.
|
|
2
|
+
|
|
3
|
+
This software and its source code (the "Software") are the proprietary and
|
|
4
|
+
confidential property of Kwik Nkap Technologies.
|
|
5
|
+
|
|
6
|
+
Kwik Nkap Technologies grants you a limited, non-exclusive, non-transferable,
|
|
7
|
+
revocable license to install and use the Software solely to integrate KwikID
|
|
8
|
+
identity verification into your applications, in accordance with your agreement
|
|
9
|
+
with Kwik Nkap Technologies.
|
|
10
|
+
|
|
11
|
+
You may not, except as expressly permitted in writing by Kwik Nkap Technologies:
|
|
12
|
+
copy, modify, or create derivative works of the Software; distribute, sublicense,
|
|
13
|
+
sell, or otherwise make the Software available to third parties other than as
|
|
14
|
+
part of your application; or reverse engineer the Software or use it to build a
|
|
15
|
+
competing product or service.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
19
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL KWIK NKAP
|
|
20
|
+
TECHNOLOGIES BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
21
|
+
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
|
22
|
+
THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,313 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @kwik-id/sdk-react-native
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
On-device identity verification (KYC) for React Native / Expo apps, by
|
|
4
|
+
[KwikID](https://identity.kwiknkap.com). The SDK runs the same flow as the KwikID web
|
|
5
|
+
SDK, natively: pick a document → photograph the front (and back) → take a selfie →
|
|
6
|
+
upload → submit. Camera capture uses
|
|
7
|
+
[`react-native-vision-camera`](https://react-native-vision-camera.com/).
|
|
8
|
+
|
|
9
|
+
> **Alpha.** This release captures documents and a selfie and submits them for
|
|
10
|
+
> verification. It does **not** yet run on-device liveness (passive or active
|
|
11
|
+
> challenges), image-quality checks, or the desktop→mobile handoff UI. Those land in
|
|
12
|
+
> later alphas. No client-side liveness result is sent with the submission. Expect
|
|
13
|
+
> breaking changes between alpha versions.
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- **Expo SDK 53** (React Native 0.79, React 19).
|
|
18
|
+
- **A custom dev build or EAS build.** The SDK uses native camera modules and
|
|
19
|
+
**does not run in Expo Go**. In Expo Go, `KwikIdRNSDK.initialize()` throws an
|
|
20
|
+
error that explains how to switch to a dev build, and the verification modal shows
|
|
21
|
+
that message.
|
|
22
|
+
- A physical device for capture testing. Simulators/emulators have no real camera.
|
|
23
|
+
- A KwikID account and API key from the [KwikID dashboard](https://identity.kwiknkap.com).
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
npx expo install @kwik-id/sdk-react-native react-native-vision-camera \
|
|
29
|
+
expo-image-manipulator expo-file-system expo-device expo-localization expo-constants
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Use `npx expo install` (not plain `npm install`) so the Expo modules resolve to the
|
|
33
|
+
versions that match your Expo SDK.
|
|
34
|
+
|
|
35
|
+
`react-native-reanimated`, `react-native-worklets-core` and
|
|
36
|
+
`react-native-vision-camera-face-detector` are optional peers for now. You don't need
|
|
37
|
+
them in this alpha; they become required once on-device liveness ships.
|
|
38
|
+
|
|
39
|
+
### 1. Add the config plugins (`app.json` / `app.config.js`)
|
|
40
|
+
|
|
41
|
+
```jsonc
|
|
42
|
+
{
|
|
43
|
+
"expo": {
|
|
44
|
+
"plugins": [
|
|
45
|
+
"react-native-vision-camera",
|
|
46
|
+
[
|
|
47
|
+
"@kwik-id/sdk-react-native",
|
|
48
|
+
{ "cameraPermissionText": "We use the camera to verify your identity" },
|
|
49
|
+
],
|
|
50
|
+
],
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The KwikID plugin adds the camera permission on both platforms
|
|
56
|
+
(`NSCameraUsageDescription` on iOS, `android.permission.CAMERA` on Android).
|
|
57
|
+
`cameraPermissionText` is optional; it is the text iOS shows in the permission prompt.
|
|
58
|
+
|
|
59
|
+
### 2. Prebuild and run a dev build
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
npx expo prebuild
|
|
63
|
+
npx expo run:ios # or: npx expo run:android
|
|
64
|
+
# or build in the cloud: eas build --profile development
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Re-run `expo prebuild` whenever you add or change config plugins.
|
|
68
|
+
|
|
69
|
+
## How it works
|
|
70
|
+
|
|
71
|
+
1. **Your backend** creates a verification session with your secret API key and gets
|
|
72
|
+
back a short-lived session `token`. Never put your API key in the app.
|
|
73
|
+
2. **Your app** passes that token to the SDK as `clientSecret` and opens the flow.
|
|
74
|
+
3. The SDK guides the user through capture, uploads the images and submits the
|
|
75
|
+
verification. `start()` resolves with `status: "submitted"` and a `jobId`.
|
|
76
|
+
4. **KwikID** processes the verification asynchronously and sends the result to your
|
|
77
|
+
backend by **webhook**. The app does not receive the final verified/rejected
|
|
78
|
+
decision.
|
|
79
|
+
|
|
80
|
+
### Create a session on your backend
|
|
81
|
+
|
|
82
|
+
With [`@kwik-id/sdk-node`](https://www.npmjs.com/package/@kwik-id/sdk-node):
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import { KwikIDNode } from "@kwik-id/sdk-node";
|
|
86
|
+
|
|
87
|
+
const kwikId = new KwikIDNode({ apiKey: process.env.KWIKID_API_KEY! });
|
|
88
|
+
|
|
89
|
+
// e.g. in your POST /kyc/session route
|
|
90
|
+
const session = await kwikId.createSession({
|
|
91
|
+
referenceId: user.id, // your own user/order ID; echoed back in webhooks
|
|
92
|
+
userName: user.name,
|
|
93
|
+
userEmail: user.email,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
return { clientSecret: session.token, jobId: session.jobId };
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Or call the REST API directly: `POST /api/v1/sessions` with an `X-API-Key` header.
|
|
100
|
+
The response's `token` is the `clientSecret`.
|
|
101
|
+
|
|
102
|
+
Session tokens expire. Create a new session for each verification attempt, just
|
|
103
|
+
before you open the flow.
|
|
104
|
+
|
|
105
|
+
## Usage
|
|
106
|
+
|
|
107
|
+
### Quick start: `useKwikVerification`
|
|
108
|
+
|
|
109
|
+
The hook gives you a `start()` function that opens the full-screen verification flow
|
|
110
|
+
and resolves when the user finishes or closes it. Render `<kyc.Modal />` once,
|
|
111
|
+
anywhere in the component.
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
import { useKwikVerification } from "@kwik-id/sdk-react-native";
|
|
115
|
+
import { Alert, Button } from "react-native";
|
|
116
|
+
|
|
117
|
+
export function VerifyIdentityButton({ clientSecret }: { clientSecret: string }) {
|
|
118
|
+
const kyc = useKwikVerification({
|
|
119
|
+
clientSecret,
|
|
120
|
+
appName: "Acme Bank", // optional: header title (defaults to your org name)
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const verify = async () => {
|
|
124
|
+
const outcome = await kyc.start();
|
|
125
|
+
|
|
126
|
+
switch (outcome.status) {
|
|
127
|
+
case "submitted":
|
|
128
|
+
// Documents are in. The final decision arrives at your backend by webhook.
|
|
129
|
+
Alert.alert("Thanks!", "Your documents were submitted for review.");
|
|
130
|
+
break;
|
|
131
|
+
case "cancelled":
|
|
132
|
+
// The user closed the flow.
|
|
133
|
+
break;
|
|
134
|
+
case "error":
|
|
135
|
+
// The flow ended on an error screen (expired session, network, etc.).
|
|
136
|
+
console.warn("KYC failed:", outcome.error?.message);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<>
|
|
143
|
+
<Button title="Verify identity" onPress={verify} />
|
|
144
|
+
<kyc.Modal />
|
|
145
|
+
</>
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Fetching the session token right before opening the flow:
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
const [clientSecret, setClientSecret] = useState("");
|
|
154
|
+
const kyc = useKwikVerification({ clientSecret });
|
|
155
|
+
|
|
156
|
+
const verify = async () => {
|
|
157
|
+
const res = await fetch("https://your-backend.example.com/kyc/session", { method: "POST" });
|
|
158
|
+
setClientSecret((await res.json()).clientSecret);
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Open once the token is in state, so the modal receives it.
|
|
162
|
+
useEffect(() => {
|
|
163
|
+
if (clientSecret) kyc.start().then(handleOutcome);
|
|
164
|
+
}, [clientSecret]);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### Options
|
|
168
|
+
|
|
169
|
+
| Option | Type | Default | Description |
|
|
170
|
+
| --------------- | ----------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
171
|
+
| `clientSecret` | `string` | **required** | Session token from your backend. |
|
|
172
|
+
| `appName` | `string` | org name from the session | Title shown in the flow's header. |
|
|
173
|
+
| `locale` | `"en" \| "fr"` | device language | UI language. If omitted, the SDK uses French when the device language is French and English otherwise. |
|
|
174
|
+
| `theme` | `KwikIdTheme` | KwikID blue on white | Colors; see [Theming](#theming). |
|
|
175
|
+
| `documentTypes` | `DocumentType[]` | all types enabled for your org | Restrict which documents the user can pick. Intersected with your session's configuration. |
|
|
176
|
+
| `onSubmitted` | `({ jobId }) => void` | none | Called as soon as the submission succeeds, before the user taps Done. |
|
|
177
|
+
| `baseUrl` | `string` | `https://api.identity.kwiknkap.com` | API base URL. Override only to target a non-production environment. |
|
|
178
|
+
| `livenessMode` | `"passive" \| "active" \| "hybrid"` | none | **Not yet supported.** Accepted but ignored until on-device liveness ships. |
|
|
179
|
+
|
|
180
|
+
#### Return value
|
|
181
|
+
|
|
182
|
+
| Field | Type | Description |
|
|
183
|
+
| -------- | ------------------------------------ | --------------------------------------------------------------------------- |
|
|
184
|
+
| `start` | `() => Promise<VerificationOutcome>` | Opens the flow. Resolves when the user finishes or closes it. |
|
|
185
|
+
| `cancel` | `() => void` | Closes the flow programmatically; a pending `start()` resolves `cancelled`. |
|
|
186
|
+
| `isOpen` | `boolean` | Whether the flow is currently open. |
|
|
187
|
+
| `Modal` | `React.FC` | Render once; the verification UI mounts here. |
|
|
188
|
+
|
|
189
|
+
#### `VerificationOutcome`
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
interface VerificationOutcome {
|
|
193
|
+
status: "submitted" | "cancelled" | "error";
|
|
194
|
+
jobId?: string; // set when status is "submitted"
|
|
195
|
+
error?: Error; // set when status is "error"
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
`"submitted"` means the documents were received, **not** that the user is verified.
|
|
200
|
+
Use the webhook (or `getVerificationResult(jobId)` in `@kwik-id/sdk-node`) to read the
|
|
201
|
+
decision.
|
|
202
|
+
|
|
203
|
+
### Declarative: `<KwikIDVerificationModal />`
|
|
204
|
+
|
|
205
|
+
If you prefer to control visibility yourself:
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
import { KwikIDVerificationModal } from "@kwik-id/sdk-react-native";
|
|
209
|
+
|
|
210
|
+
<KwikIDVerificationModal
|
|
211
|
+
visible={open}
|
|
212
|
+
clientSecret={clientSecret}
|
|
213
|
+
locale="fr"
|
|
214
|
+
onSubmitted={({ jobId }) => saveJobId(jobId)}
|
|
215
|
+
onComplete={(outcome) => {
|
|
216
|
+
setOpen(false);
|
|
217
|
+
handleOutcome(outcome);
|
|
218
|
+
}}
|
|
219
|
+
/>;
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
It takes the same options as the hook, plus `visible`, `onComplete(outcome)` (always
|
|
223
|
+
called when the flow ends, including on cancel) and `onClose()` (called only when the
|
|
224
|
+
user dismisses the flow).
|
|
225
|
+
|
|
226
|
+
### Theming
|
|
227
|
+
|
|
228
|
+
```ts
|
|
229
|
+
useKwikVerification({
|
|
230
|
+
clientSecret,
|
|
231
|
+
theme: {
|
|
232
|
+
primary: "#0F766E", // buttons, progress bar, accents (default #1E3A8A)
|
|
233
|
+
background: "#FFFFFF", // screen background
|
|
234
|
+
foreground: "#111111", // text
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The built-in flow currently uses `primary`, `background` and `foreground`. `accent`,
|
|
240
|
+
`error` and `success` are reserved for upcoming screens.
|
|
241
|
+
|
|
242
|
+
### Localization
|
|
243
|
+
|
|
244
|
+
The flow ships with **English** and **French**. Without a `locale` option it follows
|
|
245
|
+
the device language. Pass `locale` to force a language, e.g. to match an in-app
|
|
246
|
+
language setting. Other device languages fall back to English.
|
|
247
|
+
|
|
248
|
+
### Document types
|
|
249
|
+
|
|
250
|
+
`passport`, `id_card`, `drivers_license`, `voters_card` and `residence_permit`.
|
|
251
|
+
National ID cards, driver's licenses and voter's cards ask for front and back;
|
|
252
|
+
passports and residence permits need only the front. If your
|
|
253
|
+
session configuration doesn't list any document types, the user can choose from
|
|
254
|
+
passport, national ID card and driver's license.
|
|
255
|
+
|
|
256
|
+
## Error handling and timeouts
|
|
257
|
+
|
|
258
|
+
When something goes wrong, the flow shows an error screen and `start()` resolves with
|
|
259
|
+
`status: "error"` after the user taps Done. Common causes:
|
|
260
|
+
|
|
261
|
+
- **Expired session:** the user sees "Your verification session has expired." Create
|
|
262
|
+
a new session and start again.
|
|
263
|
+
- **Network problems:** each API request and each upload times out after **30
|
|
264
|
+
seconds**. For uploads the timer restarts whenever upload progress is reported, so a
|
|
265
|
+
slow upload that's still moving is not cut off; only a stalled one is cancelled.
|
|
266
|
+
- **Camera permission denied:** the flow shows a screen with an **Open Settings**
|
|
267
|
+
button. The user can grant access there and come back to continue.
|
|
268
|
+
- **Expo Go:** see [Requirements](#requirements).
|
|
269
|
+
|
|
270
|
+
## Advanced: headless SDK
|
|
271
|
+
|
|
272
|
+
`KwikIdRNSDK` is the engine behind the built-in UI. Use it if you build your own
|
|
273
|
+
capture screens. You are then responsible for capture, compression (`compressCapture`)
|
|
274
|
+
and calling the API in the right order.
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
import { KwikIdRNSDK } from "@kwik-id/sdk-react-native";
|
|
278
|
+
|
|
279
|
+
const sdk = new KwikIdRNSDK({ clientSecret, timeout: 30_000, debug: __DEV__ });
|
|
280
|
+
|
|
281
|
+
const session = await sdk.initialize(); // validates the token; throws in Expo Go
|
|
282
|
+
sdk.on("upload:progress", ({ type, progress }) => console.log(type, progress));
|
|
283
|
+
|
|
284
|
+
await sdk.uploadCapture("document_front", frontAsset);
|
|
285
|
+
await sdk.uploadCapture("document_back", backAsset); // not for passports
|
|
286
|
+
await sdk.uploadCapture("selfie", selfieAsset);
|
|
287
|
+
const { jobId } = await sdk.submit("id_card");
|
|
288
|
+
|
|
289
|
+
sdk.destroy();
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Events emitted today: `ready`, `error`, `session:created`, `upload:starting`,
|
|
293
|
+
`upload:progress`, `upload:complete`, `upload:failed`, `verification:submitting`,
|
|
294
|
+
`verification:submitted`, `verification:failed`. The other event names in
|
|
295
|
+
`KwikIdEvents` are reserved for liveness and handoff and are not emitted yet.
|
|
296
|
+
|
|
297
|
+
`CameraView` (the capture component used by the built-in flow) is also exported for
|
|
298
|
+
custom screens.
|
|
299
|
+
|
|
300
|
+
## Troubleshooting
|
|
301
|
+
|
|
302
|
+
| Symptom | Fix |
|
|
303
|
+
| --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
304
|
+
| "This SDK requires a custom dev build or EAS build" | You're in Expo Go. Run `npx expo prebuild` and `npx expo run:ios` / `run:android`, or use an EAS dev build. |
|
|
305
|
+
| Camera preview is black / no camera found | Use a physical device, and check that the vision-camera and KwikID plugins are in `app.json`, then rebuild. |
|
|
306
|
+
| iOS crashes when the camera opens | `NSCameraUsageDescription` is missing: add the KwikID config plugin and re-run `expo prebuild`. |
|
|
307
|
+
| "Your verification session has expired" | Session tokens are short-lived. Create a new session right before calling `start()`. |
|
|
308
|
+
|
|
309
|
+
## License
|
|
310
|
+
|
|
311
|
+
Proprietary. Copyright © 2026 Kwik Nkap Technologies. All rights reserved. Use is
|
|
312
|
+
subject to the terms in the [LICENSE](./LICENSE) file and your agreement with Kwik Nkap
|
|
313
|
+
Technologies.
|
package/app.plugin.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Expo config plugin for @kwik-id/sdk-react-native.
|
|
3
|
+
*
|
|
4
|
+
* Adds the native camera permissions required by react-native-vision-camera.
|
|
5
|
+
* Babel-level requirements (react-native-worklets-core/plugin and
|
|
6
|
+
* react-native-reanimated/plugin) live in the consumer's babel.config.js — see README.
|
|
7
|
+
*
|
|
8
|
+
* Usage (app.json):
|
|
9
|
+
* "plugins": [
|
|
10
|
+
* "react-native-vision-camera",
|
|
11
|
+
* ["@kwik-id/sdk-react-native", { "cameraPermissionText": "..." }]
|
|
12
|
+
* ]
|
|
13
|
+
*
|
|
14
|
+
* NOTE: requires `expo prebuild` + a custom dev build / EAS build. Will NOT run in Expo Go.
|
|
15
|
+
*/
|
|
16
|
+
const { withInfoPlist, withAndroidManifest, AndroidConfig } = require("expo/config-plugins");
|
|
17
|
+
|
|
18
|
+
const DEFAULT_CAMERA_TEXT = "We need camera access to verify your identity";
|
|
19
|
+
|
|
20
|
+
/** @param {import('expo/config-plugins').ExpoConfig} config */
|
|
21
|
+
const withKwikId = (config, props = {}) => {
|
|
22
|
+
const cameraPermissionText = props.cameraPermissionText || DEFAULT_CAMERA_TEXT;
|
|
23
|
+
|
|
24
|
+
// iOS — NSCameraUsageDescription
|
|
25
|
+
config = withInfoPlist(config, (cfg) => {
|
|
26
|
+
cfg.modResults.NSCameraUsageDescription =
|
|
27
|
+
cfg.modResults.NSCameraUsageDescription || cameraPermissionText;
|
|
28
|
+
return cfg;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// Android — CAMERA permission
|
|
32
|
+
config = withAndroidManifest(config, (cfg) => {
|
|
33
|
+
AndroidConfig.Permissions.ensurePermissions(cfg.modResults, ["android.permission.CAMERA"]);
|
|
34
|
+
return cfg;
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return config;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
module.exports = withKwikId;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.DEFAULT_BASE_URL = exports.ApiClient = void 0;
|
|
7
|
+
var _apiError = require("./api-error.js");
|
|
8
|
+
var _upload = require("./upload.js");
|
|
9
|
+
/**
|
|
10
|
+
* RN API client for the KwikId SDK gateway (`/sdk/v1/*`).
|
|
11
|
+
*
|
|
12
|
+
* Ported from @kwik-id/sdk-core: the JSON `request()` (fetch + AbortController) is
|
|
13
|
+
* unchanged; the XMLHttpRequest upload is replaced with an injectable multipart
|
|
14
|
+
* uploader (expo-file-system by default). `liveness_frame` has no server endpoint
|
|
15
|
+
* and is rejected.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const DEFAULT_BASE_URL = exports.DEFAULT_BASE_URL = "https://api.identity.kwiknkap.com";
|
|
19
|
+
const CAPTURE_PATH = {
|
|
20
|
+
document_front: "front",
|
|
21
|
+
document_back: "back",
|
|
22
|
+
selfie: "selfie",
|
|
23
|
+
liveness_frame: null // no server endpoint — liveness evidence rides in /submit
|
|
24
|
+
};
|
|
25
|
+
class ApiClient {
|
|
26
|
+
constructor(sessionManager, config) {
|
|
27
|
+
this.config = {
|
|
28
|
+
baseUrl: DEFAULT_BASE_URL,
|
|
29
|
+
timeout: 30000,
|
|
30
|
+
debug: false,
|
|
31
|
+
...config
|
|
32
|
+
};
|
|
33
|
+
this.sessionManager = sessionManager;
|
|
34
|
+
this.uploader = config?.uploader ?? _upload.uploadMultipart;
|
|
35
|
+
}
|
|
36
|
+
async validateSession(clientSecret) {
|
|
37
|
+
await this.sessionManager.initializeFromClientSecret(clientSecret);
|
|
38
|
+
const response = await this.request("GET", "/sdk/v1/session");
|
|
39
|
+
this.sessionManager.updateSession({
|
|
40
|
+
expiresAt: new Date(response.expiresAt)
|
|
41
|
+
});
|
|
42
|
+
return response;
|
|
43
|
+
}
|
|
44
|
+
async uploadCapture(type, asset, onProgress) {
|
|
45
|
+
const path = CAPTURE_PATH[type];
|
|
46
|
+
if (!path) {
|
|
47
|
+
throw new Error(`Unsupported capture type for upload: ${type}`);
|
|
48
|
+
}
|
|
49
|
+
const url = `${this.config.baseUrl}/sdk/v1/upload/${path}`;
|
|
50
|
+
const headers = this.sessionManager.getRequestHeaders();
|
|
51
|
+
return this.uploader({
|
|
52
|
+
url,
|
|
53
|
+
asset,
|
|
54
|
+
headers,
|
|
55
|
+
onProgress,
|
|
56
|
+
timeoutMs: this.config.timeout
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async submitVerification(documentType, clientAnalysis) {
|
|
60
|
+
const payload = await this.sessionManager.createSecurePayload({
|
|
61
|
+
documentType,
|
|
62
|
+
clientAnalysis,
|
|
63
|
+
submittedAt: Date.now()
|
|
64
|
+
});
|
|
65
|
+
return this.request("POST", "/sdk/v1/submit", payload);
|
|
66
|
+
}
|
|
67
|
+
async getStatus() {
|
|
68
|
+
return this.request("GET", "/sdk/v1/status");
|
|
69
|
+
}
|
|
70
|
+
async getResult() {
|
|
71
|
+
return this.request("GET", "/sdk/v1/result");
|
|
72
|
+
}
|
|
73
|
+
async pollForResult(options = {}) {
|
|
74
|
+
const {
|
|
75
|
+
maxAttempts = 60,
|
|
76
|
+
intervalMs = 2000,
|
|
77
|
+
onProgress
|
|
78
|
+
} = options;
|
|
79
|
+
let attempts = 0;
|
|
80
|
+
while (attempts < maxAttempts) {
|
|
81
|
+
const status = await this.getStatus();
|
|
82
|
+
onProgress?.(status);
|
|
83
|
+
if (status.status === "verified") {
|
|
84
|
+
return this.getResult();
|
|
85
|
+
}
|
|
86
|
+
if (status.status === "rejected") {
|
|
87
|
+
const result = await this.getResult();
|
|
88
|
+
const contextualError = status.errorDetails ? `${status.errorDetails.document === "front" ? "Front" : "Back"} document: ${status.errorDetails.errorMessage}` : undefined;
|
|
89
|
+
return {
|
|
90
|
+
...result,
|
|
91
|
+
status: "rejected",
|
|
92
|
+
errorDetails: status.errorDetails,
|
|
93
|
+
rejectionReasons: [contextualError || status.errorMessage || "Verification rejected"]
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
if (status.status === "failed") {
|
|
97
|
+
// A failed job may have no result record, so fall back to a minimal one.
|
|
98
|
+
const result = await this.getResult().catch(() => ({
|
|
99
|
+
jobId: status.jobId,
|
|
100
|
+
status: "rejected",
|
|
101
|
+
overallScore: 0,
|
|
102
|
+
scores: {
|
|
103
|
+
documentQuality: 0,
|
|
104
|
+
documentAuthenticity: 0,
|
|
105
|
+
faceMatch: 0,
|
|
106
|
+
liveness: 0
|
|
107
|
+
},
|
|
108
|
+
timestamps: {
|
|
109
|
+
submitted: ""
|
|
110
|
+
},
|
|
111
|
+
referenceId: ""
|
|
112
|
+
}));
|
|
113
|
+
return {
|
|
114
|
+
...result,
|
|
115
|
+
// VerificationResult has no "failed" status (it mirrors sdk-core).
|
|
116
|
+
status: "rejected",
|
|
117
|
+
errorDetails: status.errorDetails,
|
|
118
|
+
rejectionReasons: [status.errorDetails?.errorMessage || status.errorMessage || "Verification failed"]
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
attempts++;
|
|
122
|
+
await this.delay(intervalMs);
|
|
123
|
+
}
|
|
124
|
+
throw new Error("Verification timeout");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// ---- Handoff (mobile redeemer) ----
|
|
128
|
+
|
|
129
|
+
async validateHandoff(code) {
|
|
130
|
+
const url = `${this.config.baseUrl}/sdk/v1/handoff/${encodeURIComponent(code)}`;
|
|
131
|
+
const fetchFn = this.config.fetch || fetch;
|
|
132
|
+
const response = await fetchFn(url);
|
|
133
|
+
if (!response.ok) {
|
|
134
|
+
return {
|
|
135
|
+
valid: false,
|
|
136
|
+
error: `Validation failed: ${response.status}`
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
return await response.json();
|
|
140
|
+
}
|
|
141
|
+
async redeemHandoff(code) {
|
|
142
|
+
const url = `${this.config.baseUrl}/sdk/v1/handoff/${encodeURIComponent(code)}/redeem`;
|
|
143
|
+
const fetchFn = this.config.fetch || fetch;
|
|
144
|
+
const response = await fetchFn(url, {
|
|
145
|
+
method: "POST",
|
|
146
|
+
headers: {
|
|
147
|
+
"Content-Type": "application/json"
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
if (!response.ok) {
|
|
151
|
+
const error = await response.json().catch(() => ({}));
|
|
152
|
+
throw new _apiError.ApiError(error.message || `Redeem failed: ${response.status}`, response.status);
|
|
153
|
+
}
|
|
154
|
+
return await response.json();
|
|
155
|
+
}
|
|
156
|
+
async reportHandoffStatus(code, status) {
|
|
157
|
+
await this.request("POST", `/sdk/v1/handoff/${encodeURIComponent(code)}/status`, {
|
|
158
|
+
status
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
getBaseUrl() {
|
|
162
|
+
return this.config.baseUrl;
|
|
163
|
+
}
|
|
164
|
+
async request(method, path, body) {
|
|
165
|
+
const url = `${this.config.baseUrl}${path}`;
|
|
166
|
+
const controller = new AbortController();
|
|
167
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
168
|
+
try {
|
|
169
|
+
const headers = {
|
|
170
|
+
"Content-Type": "application/json",
|
|
171
|
+
...this.sessionManager.getRequestHeaders()
|
|
172
|
+
};
|
|
173
|
+
const fetchFn = this.config.fetch || fetch;
|
|
174
|
+
const response = await fetchFn(url, {
|
|
175
|
+
method,
|
|
176
|
+
headers,
|
|
177
|
+
body: body ? JSON.stringify(body) : undefined,
|
|
178
|
+
signal: controller.signal
|
|
179
|
+
});
|
|
180
|
+
clearTimeout(timeoutId);
|
|
181
|
+
if (!response.ok) {
|
|
182
|
+
throw await this.parseErrorResponse(response);
|
|
183
|
+
}
|
|
184
|
+
const data = await response.json();
|
|
185
|
+
if (this.config.debug) {
|
|
186
|
+
console.log(`[KwikID API] ${method} ${path}`, {
|
|
187
|
+
body,
|
|
188
|
+
response: data
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
return data;
|
|
192
|
+
} catch (error) {
|
|
193
|
+
clearTimeout(timeoutId);
|
|
194
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
195
|
+
throw new Error("Request timeout");
|
|
196
|
+
}
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
async parseErrorResponse(response) {
|
|
201
|
+
try {
|
|
202
|
+
const data = await response.json();
|
|
203
|
+
return new _apiError.ApiError(data.message || `API error: ${response.status}`, response.status, data.code, data.details);
|
|
204
|
+
} catch {
|
|
205
|
+
return new _apiError.ApiError(`API error: ${response.status}`, response.status);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
delay(ms) {
|
|
209
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
exports.ApiClient = ApiClient;
|
|
213
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["_apiError","require","_upload","DEFAULT_BASE_URL","exports","CAPTURE_PATH","document_front","document_back","selfie","liveness_frame","ApiClient","constructor","sessionManager","config","baseUrl","timeout","debug","uploader","uploadMultipart","validateSession","clientSecret","initializeFromClientSecret","response","request","updateSession","expiresAt","Date","uploadCapture","type","asset","onProgress","path","Error","url","headers","getRequestHeaders","timeoutMs","submitVerification","documentType","clientAnalysis","payload","createSecurePayload","submittedAt","now","getStatus","getResult","pollForResult","options","maxAttempts","intervalMs","attempts","status","result","contextualError","errorDetails","document","errorMessage","undefined","rejectionReasons","catch","jobId","overallScore","scores","documentQuality","documentAuthenticity","faceMatch","liveness","timestamps","submitted","referenceId","delay","validateHandoff","code","encodeURIComponent","fetchFn","fetch","ok","valid","error","json","redeemHandoff","method","ApiError","message","reportHandoffStatus","getBaseUrl","body","controller","AbortController","timeoutId","setTimeout","abort","JSON","stringify","signal","clearTimeout","parseErrorResponse","data","console","log","name","details","ms","Promise","resolve"],"sourceRoot":"../../../src","sources":["api/api-client.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.ApiError = void 0;
|
|
7
|
+
/**
|
|
8
|
+
* API error (ported verbatim from @kwik-id/sdk-core).
|
|
9
|
+
*/
|
|
10
|
+
class ApiError extends Error {
|
|
11
|
+
constructor(message, statusCode, code, details) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "ApiError";
|
|
14
|
+
this.statusCode = statusCode;
|
|
15
|
+
this.code = code;
|
|
16
|
+
this.details = details;
|
|
17
|
+
}
|
|
18
|
+
isRetryable() {
|
|
19
|
+
return this.statusCode >= 500 || this.statusCode === 429;
|
|
20
|
+
}
|
|
21
|
+
isAuthError() {
|
|
22
|
+
return this.statusCode === 401 || this.statusCode === 403;
|
|
23
|
+
}
|
|
24
|
+
isValidationError() {
|
|
25
|
+
return this.statusCode === 400 || this.statusCode === 422;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.ApiError = ApiError;
|
|
29
|
+
//# sourceMappingURL=api-error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["ApiError","Error","constructor","message","statusCode","code","details","name","isRetryable","isAuthError","isValidationError","exports"],"sourceRoot":"../../../src","sources":["api/api-error.ts"],"mappings":";;;;;;AAAA;AACA;AACA;AACO,MAAMA,QAAQ,SAASC,KAAK,CAAC;EAKhCC,WAAWA,CAACC,OAAe,EAAEC,UAAkB,EAAEC,IAAa,EAAEC,OAAiB,EAAE;IAC/E,KAAK,CAACH,OAAO,CAAC;IACd,IAAI,CAACI,IAAI,GAAG,UAAU;IACtB,IAAI,CAACH,UAAU,GAAGA,UAAU;IAC5B,IAAI,CAACC,IAAI,GAAGA,IAAI;IAChB,IAAI,CAACC,OAAO,GAAGA,OAAO;EAC1B;EAEAE,WAAWA,CAAA,EAAY;IACnB,OAAO,IAAI,CAACJ,UAAU,IAAI,GAAG,IAAI,IAAI,CAACA,UAAU,KAAK,GAAG;EAC5D;EAEAK,WAAWA,CAAA,EAAY;IACnB,OAAO,IAAI,CAACL,UAAU,KAAK,GAAG,IAAI,IAAI,CAACA,UAAU,KAAK,GAAG;EAC7D;EAEAM,iBAAiBA,CAAA,EAAY;IACzB,OAAO,IAAI,CAACN,UAAU,KAAK,GAAG,IAAI,IAAI,CAACA,UAAU,KAAK,GAAG;EAC7D;AACJ;AAACO,OAAA,CAAAX,QAAA,GAAAA,QAAA","ignoreList":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "ApiClient", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _apiClient.ApiClient;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "ApiError", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _apiError.ApiError;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
Object.defineProperty(exports, "DEFAULT_BASE_URL", {
|
|
19
|
+
enumerable: true,
|
|
20
|
+
get: function () {
|
|
21
|
+
return _apiClient.DEFAULT_BASE_URL;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
Object.defineProperty(exports, "uploadMultipart", {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () {
|
|
27
|
+
return _upload.uploadMultipart;
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
var _apiClient = require("./api-client.js");
|
|
31
|
+
var _apiError = require("./api-error.js");
|
|
32
|
+
var _upload = require("./upload.js");
|
|
33
|
+
//# sourceMappingURL=index.js.map
|