@kwik-id/sdk-react 0.1.0-alpha.3 → 0.1.0-alpha.7

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @kwik-id/sdk-react
2
2
 
3
- React SDK for [KwikID](https://kwik-id.com) identity verification. Drop-in components and hooks for adding KYC verification to your React application.
3
+ SDK for [KwikID](https://identity.kwiknkap.com) identity verification. Adds a complete KYC verification flow to any web application with a single function call.
4
4
 
5
5
  ## Installation
6
6
 
@@ -12,15 +12,13 @@ pnpm add @kwik-id/sdk-react
12
12
  yarn add @kwik-id/sdk-react
13
13
  ```
14
14
 
15
- **Peer dependencies:** `react >= 18`, `react-dom >= 18`, `framer-motion >= 10`, `lucide-react >= 0.300`
15
+ **Peer dependencies:** `react >= 18`, `react-dom >= 18`, `framer-motion >= 10`, `lucide-react >= 0.300`, `lottie-react >= 2.4`
16
16
 
17
17
  ## Quick Start
18
18
 
19
- The fastest way to add verification is the `<KwikID>` component — a complete, pre-built verification flow.
20
-
21
19
  ### 1. Create a session on your backend
22
20
 
23
- Use [`@kwik-id/sdk-node`](https://www.npmjs.com/package/@kwik-id/sdk-node) to create a session server-side:
21
+ > **Security:** Sessions must be created server-side. Your API key must never be exposed to the browser. Use [`@kwik-id/sdk-node`](https://www.npmjs.com/package/@kwik-id/sdk-node) or a direct API call from your backend to get a short-lived `clientSecret` (session token) to pass to the frontend.
24
22
 
25
23
  ```ts
26
24
  // Backend (Express, Next.js API route, etc.)
@@ -37,63 +35,68 @@ app.post("/api/create-session", async (req, res) => {
37
35
  });
38
36
  ```
39
37
 
40
- ### 2. Use the KwikID component in your frontend
38
+ ### 2. Open the verification modal
41
39
 
42
- ```tsx
43
- import { KwikID } from "@kwik-id/sdk-react";
40
+ Call `openKwikVerification()` from any button click or event handler. It injects the modal at `document.body` — zero layout impact on your page — and returns a Promise that resolves when the user finishes or exits.
44
41
 
45
- function VerificationPage() {
46
- const [clientSecret, setClientSecret] = useState<string | null>(null);
42
+ ```ts
43
+ import { openKwikVerification } from "@kwik-id/sdk-react";
47
44
 
48
- useEffect(() => {
49
- fetch("/api/create-session", { method: "POST" })
50
- .then((res) => res.json())
51
- .then((data) => setClientSecret(data.clientSecret));
52
- }, []);
45
+ // Works in React, Vue, Angular, or plain JavaScript
46
+ async function handleVerifyClick() {
47
+ const { clientSecret } = await fetch("/api/create-session", { method: "POST" }).then((r) =>
48
+ r.json()
49
+ );
53
50
 
54
- if (!clientSecret) return <div>Loading...</div>;
51
+ const { status, jobId } = await openKwikVerification({
52
+ clientSecret,
53
+ appName: "My App",
54
+ theme: { primary: "#2563EB", accent: "#FBBF24" },
55
+ onSubmitted: ({ jobId }) => {
56
+ // Fires while modal is still open — save the jobId immediately.
57
+ // The actual verification result (pass/fail) arrives later via webhook.
58
+ console.log("Submitted for review, jobId:", jobId);
59
+ },
60
+ });
55
61
 
56
- return (
57
- <KwikID
58
- config={{
59
- clientSecret,
60
- appName: "My App",
61
- theme: { primary: "#2563EB", accent: "#FBBF24" },
62
- onSubmitted: ({ jobId }) => {
63
- // Fires immediately when documents are uploaded and background
64
- // processing begins. Save the jobId to track status via webhooks.
65
- console.log("Submitted for review, jobId:", jobId);
66
- },
67
- onComplete: (data) => {
68
- // Fires when the user dismisses the result screen (clicks "Done").
69
- // Use this to redirect or clean up.
70
- console.log("User dismissed verification modal", data);
71
- },
72
- onError: (error) => {
73
- console.error("Verification error:", error);
74
- },
75
- }}
76
- />
77
- );
62
+ if (status === "submitted") {
63
+ // Modal closed. Documents are with the backend.
64
+ // Listen for the result via your webhook endpoint.
65
+ showMessage("We'll notify you once your identity is verified.");
66
+ } else if (status === "cancelled") {
67
+ // User closed the modal before submitting.
68
+ } else if (status === "error") {
69
+ // Upload or submission failed.
70
+ }
78
71
  }
79
72
  ```
80
73
 
81
- That's it — the component handles the full flow: document selection, camera capture, quality checks, face detection, liveness, and submission. The modal opens automatically when the component renders.
74
+ That's it — the modal handles the full flow: document selection, camera capture, quality checks, liveness, and submission.
75
+
76
+ > **Note:** `status === "submitted"` means documents were received by the backend and processing has started — **not** that the verification passed. The pass/fail result arrives asynchronously via [webhooks](#webhooks).
82
77
 
83
78
  ## Configuration
84
79
 
85
- ### `KwikIDConfig`
80
+ ### `OpenVerificationOptions`
81
+
82
+ | Option | Type | Required | Description |
83
+ | -------------- | --------------------- | -------- | ------------------------------------------------------------------------------------------------- |
84
+ | `clientSecret` | `string` | Yes | Session token from your backend |
85
+ | `appName` | `string` | No | App name shown in the modal header (falls back to org name) |
86
+ | `baseUrl` | `string` | No | API base URL (defaults to production) |
87
+ | `theme` | `KwikIDTheme` | No | Custom theme colors |
88
+ | `showLogo` | `boolean` | No | Show org logo in header (default: `true`) |
89
+ | `onSubmitted` | `({ jobId }) => void` | No | Called while the modal is still open, immediately when documents are uploaded. Save `jobId` here. |
90
+
91
+ ### `VerificationOutcome`
92
+
93
+ Resolved value of the Promise returned by `openKwikVerification()`:
86
94
 
87
- | Prop | Type | Required | Description |
88
- | -------------- | ------------------------ | -------- | -------------------------------------------------------------------------------------------------------------- |
89
- | `clientSecret` | `string` | Yes | Session token from your backend |
90
- | `appName` | `string` | No | App name shown in the header (falls back to org name) |
91
- | `baseUrl` | `string` | No | API base URL (defaults to production) |
92
- | `theme` | `KwikIDTheme` | No | Custom theme colors |
93
- | `showLogo` | `boolean` | No | Show org logo in header (default: `true`) |
94
- | `onSubmitted` | `({ jobId }) => void` | No | Called immediately when documents are uploaded and background processing begins. Use this to save the `jobId`. |
95
- | `onComplete` | `(data) => void` | No | Called when the user dismisses the result screen (clicks "Done") |
96
- | `onError` | `(error: Error) => void` | No | Called on errors |
95
+ | Field | Type | Description |
96
+ | -------- | --------------------------------------- | ---------------------------------------------------- |
97
+ | `status` | `"submitted" \| "cancelled" \| "error"` | What happened when the modal closed |
98
+ | `jobId` | `string` | Present on `"submitted"` use to track via webhooks |
99
+ | `error` | `Error` | Present on `"cancelled"` and `"error"` |
97
100
 
98
101
  ### `KwikIDTheme`
99
102
 
@@ -106,159 +109,57 @@ That's it — the component handles the full flow: document selection, camera ca
106
109
  }
107
110
  ```
108
111
 
109
- ## Components
112
+ ## React Component (alternative)
110
113
 
111
- ### `<KwikID>` — Drop-in Verification
112
-
113
- The all-in-one component. Renders a complete verification flow with document selection, camera capture, quality feedback, liveness detection, and submission.
114
+ If you prefer a declarative React approach, `<KwikID>` is available. It renders the same modal as `openKwikVerification()` mount it conditionally, unmount it to close.
114
115
 
115
116
  ```tsx
116
- <KwikID config={{ clientSecret, appName: "My App" }} />
117
- ```
118
-
119
- ### `<KYCModalFlow>` — Modal Verification
120
-
121
- Renders the verification flow inside a modal dialog with step indicators.
122
-
123
- ```tsx
124
- import { KYCModalFlow } from "@kwik-id/sdk-react";
125
- ```
126
-
127
- ### `<KwikIDProvider>` — Context Provider
128
-
129
- For custom integrations, wrap your components with the provider to access SDK state via hooks.
130
-
131
- ```tsx
132
- import { KwikIDProvider, useKwikID } from "@kwik-id/sdk-react";
117
+ import { KwikID } from "@kwik-id/sdk-react";
133
118
 
134
- function App() {
135
- return (
136
- <KwikIDProvider config={{ clientSecret, appName: "My App" }} clientSecret={clientSecret}>
137
- <CustomVerificationFlow />
138
- </KwikIDProvider>
119
+ {
120
+ showVerification && (
121
+ <KwikID
122
+ config={{
123
+ clientSecret,
124
+ appName: "My App",
125
+ onSubmitted: ({ jobId }) => saveJobId(jobId),
126
+ onComplete: () => setShowVerification(false),
127
+ onError: () => setShowVerification(false),
128
+ }}
129
+ />
139
130
  );
140
131
  }
141
-
142
- function CustomVerificationFlow() {
143
- const {
144
- sdk,
145
- isSDKReady,
146
- qualityResult,
147
- detectedFace,
148
- analyzeQuality,
149
- detectFace,
150
- submitVerification,
151
- } = useKwikID();
152
-
153
- // Build your own UI using SDK state and actions
154
- }
155
132
  ```
156
133
 
157
- ### Individual Steps
158
-
159
- Build custom flows by composing individual step components:
160
-
161
- ```tsx
162
- import {
163
- CameraCapture,
164
- ConsentStep,
165
- DocumentTypeSelection,
166
- IntroStep,
167
- PhotoConfirmation,
168
- PrepareIDBack,
169
- PrepareIDFront,
170
- PrepareSelfie,
171
- SelfieConfirmation,
172
- } from "@kwik-id/sdk-react";
173
- ```
134
+ ### `<KwikIDProvider>` — Context Provider
174
135
 
175
- ### Cross-Device Handoff
136
+ Wraps your components to provide SDK state and actions via the `useKwikID()` hook. Used internally by both `openKwikVerification()` and `<KwikID>`.
176
137
 
177
- Let desktop users continue verification on their phone:
138
+ > **Note:** Building a fully custom verification flow with this provider (custom camera UI, custom step sequencing, cross-device handoff) requires significant implementation work. Detailed documentation for custom integrations is coming.
178
139
 
179
- ```tsx
180
- import { HandoffChoiceView, HandoffQRView, useHandoff } from "@kwik-id/sdk-react";
181
- ```
140
+ `useKwikID()` returns: `isSDKReady`, `orgName`, `orgLogoUrl`, `qualityResult`, `detectedFace`, `alignmentResult`, `livenessResult`, `analyzeQuality(video)`, `detectFace(video)`, `checkAlignment()`, `runPassiveLiveness()`, `submitVerification(docType)`, `uploadFile(type, file)`.
182
141
 
183
142
  ## Hooks
184
143
 
185
- For advanced custom integrations, use hooks directly:
186
-
187
- ### `useKwikId(config)`
188
-
189
- Core hook that manages the full SDK lifecycle.
190
-
191
- ```tsx
192
- const { sdk, state, status, submit, captures, events } = useKwikId({
193
- clientSecret,
194
- baseUrl: "https://api.kwik-id.com",
195
- });
196
- ```
197
-
198
- ### `useCamera(options)`
199
-
200
- Camera access and frame capture.
201
-
202
- ```tsx
203
- const { videoRef, stream, start, stop, capture } = useCamera({
204
- facingMode: "environment",
205
- width: 1280,
206
- height: 720,
207
- });
208
- ```
144
+ The following hooks are exported. They are used internally by the built-in components and are available for custom integrations. Hooks marked **requires provider** must be used inside `<KwikIDProvider>`.
209
145
 
210
- ### `useQuality(options)`
211
-
212
- Real-time image quality analysis.
213
-
214
- ```tsx
215
- const { analyze, result, isAcceptable } = useQuality({
216
- minBrightness: 0.3,
217
- maxBrightness: 0.9,
218
- });
219
- ```
220
-
221
- ### `useFaceDetection(options)`
222
-
223
- Face detection and alignment feedback.
224
-
225
- ```tsx
226
- const { detect, face, alignment, isAligned } = useFaceDetection();
227
- ```
228
-
229
- ### `useLiveness(options)`
230
-
231
- Passive and active liveness detection.
232
-
233
- ```tsx
234
- const { check, result, isLive } = useLiveness();
235
- ```
236
-
237
- ### `useVerification(options)`
238
-
239
- Full verification workflow state machine.
240
-
241
- ```tsx
242
- const { step, next, back, submit, isComplete } = useVerification({
243
- clientSecret,
244
- onComplete: (data) => console.log("Done", data),
245
- });
246
- ```
247
-
248
- ### `useHandoff()`
249
-
250
- Cross-device handoff (QR code transfer from desktop to mobile).
251
-
252
- ```tsx
253
- const { startHandoff, handoffState, handoffUrl } = useHandoff();
254
- ```
146
+ | Hook | Requires provider | Description |
147
+ | --------------------------- | ----------------- | ---------------------------------------------------- |
148
+ | `useKwikID()` | Yes | Full SDK state and actions (camera, capture, submit) |
149
+ | `useCamera(options)` | No | Camera access and frame capture |
150
+ | `useQuality(options)` | No | Real-time image quality analysis |
151
+ | `useFaceDetection(options)` | No | Face detection and alignment |
152
+ | `useLiveness(options)` | No | Passive liveness detection |
153
+ | `useVerification(options)` | Yes | Verification step state machine |
154
+ | `useHandoff()` | Yes | Cross-device QR handoff |
255
155
 
256
156
  ## Utilities
257
157
 
258
158
  ```tsx
259
159
  import {
260
160
  // Check image sharpness
261
- UploadManager, // Manage file uploads
161
+ UploadManager,
162
+ // Manage file uploads
262
163
  // Compress images before upload
263
164
  analyzeImageQuality,
264
165
  // Check image brightness
@@ -1,5 +1,5 @@
1
1
  import { AlignmentResult, DetectedFace, KwikIdSDK, PassiveLivenessResult, QualityResult } from '../../../sdk-core/src/index.ts';
2
- import { KwikIDConfig } from '../../../types/src/index.ts';
2
+ import { KwikIDConfig } from '../../../types/src';
3
3
  /**
4
4
  * Extended context value that includes SDK functionality
5
5
  */
package/dist/index.d.ts CHANGED
@@ -5,6 +5,8 @@
5
5
  *
6
6
  * @packageDocumentation
7
7
  */
8
+ export { openKwikVerification } from './open-kwik-verification';
9
+ export type { OpenVerificationOptions, VerificationOutcome } from './open-kwik-verification';
8
10
  export { KwikIDProvider, KwikIDContext, useKwikID } from './hooks/kwik-id-context';
9
11
  export { KwikIdProvider, useKwikIdContext } from './context/kwik-id-context';
10
12
  export type { KwikIdProviderProps, KwikIdContextState, KwikIdContextActions, KwikIdContextValue, } from './context/kwik-id-context';
@@ -35,5 +37,5 @@ export { compressImage } from './utils/image-compression';
35
37
  export { analyzeImageQuality, checkLuminance, checkBlur, getImageDataFromVideo, getImageDataFromFile, type ImageQualityResult, type QualityCheckResult, } from './utils/image-quality';
36
38
  export { UploadManager } from './utils/upload-manager';
37
39
  export type { KwikIdConfig, KwikIdTheme, QualityResult, QualityGuidance, DetectedFace, BoundingBox, FacePose, AlignmentResult, AlignmentGuidance, PassiveLivenessResult, Challenge, ChallengeType, ChallengeResult, VerificationResult, SDKState, SDKStatus, } from '../../sdk-core/src/index.ts';
38
- export type { KwikIDConfig, KwikIDTheme, KYCFormData, ConsentData, DocumentData, SelfieData, } from '../../types/src/index.ts';
40
+ export type { KwikIDConfig, KwikIDTheme, KYCFormData, ConsentData, DocumentData, SelfieData, } from '../../types/src';
39
41
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAGnF,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7E,YAAY,EACR,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,GACrB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EACH,SAAS,EACT,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,eAAe,GAClB,MAAM,SAAS,CAAC;AACjB,YAAY,EACR,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACrB,gBAAgB,GACnB,MAAM,SAAS,CAAC;AAGjB,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,KAAK,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,8CAA8C,CAAC;AACrF,OAAO,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAG9E,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAGxE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EACH,mBAAmB,EACnB,cAAc,EACd,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,GAC1B,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAOvD,YAAY,EACR,YAAY,EACZ,WAAW,EACX,aAAa,EACb,eAAe,EACf,YAAY,EACZ,WAAW,EACX,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,qBAAqB,EACrB,SAAS,EACT,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,QAAQ,EACR,SAAS,GACZ,MAAM,mBAAmB,CAAC;AAG3B,YAAY,EACR,YAAY,EACZ,WAAW,EACX,WAAW,EACX,WAAW,EACX,YAAY,EACZ,UAAU,GACb,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}