@flonkid/kyc 1.4.1 → 1.5.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 +77 -33
- package/dist/index.cjs +33 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.js +33 -35
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,45 +11,66 @@ Official SDK for [Flonk](https://flonk.id) identity verification.
|
|
|
11
11
|
npm install @flonkid/kyc
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
| Import | Use |
|
|
15
|
+
|--------|-----|
|
|
16
|
+
| `@flonkid/kyc` | Browser — widget + React component |
|
|
17
|
+
| `@flonkid/kyc/server` | Node.js — sessions API + webhook verification |
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
import { FlonkKYC } from '@flonkid/kyc';
|
|
19
|
+
## React Component (recommended)
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
const widget = await kyc.init({
|
|
21
|
-
publishableKey: 'pk_live_...',
|
|
22
|
-
onSuccess: (result) => console.log('Verified:', result),
|
|
23
|
-
onError: (err) => console.error(err),
|
|
24
|
-
});
|
|
21
|
+
### Option A: SDK handles session creation
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
```tsx
|
|
24
|
+
import { FlonkKYCWidget } from '@flonkid/kyc';
|
|
25
|
+
|
|
26
|
+
<FlonkKYCWidget
|
|
27
|
+
serverUrl="/api/kyc/create-session"
|
|
28
|
+
clientMetadata={{ email: 'user@example.com', userId: 'user_123' }}
|
|
29
|
+
lang="de"
|
|
30
|
+
onSuccess={(result) => console.log('Verified:', result)}
|
|
31
|
+
onError={(error) => console.error(error)}
|
|
32
|
+
onCancel={() => console.log('Cancelled')}
|
|
33
|
+
/>
|
|
34
|
+
|
|
35
|
+
// With authenticated backend
|
|
36
|
+
<FlonkKYCWidget
|
|
37
|
+
serverUrl="/api/kyc/create-session"
|
|
38
|
+
requestHeaders={{ Authorization: `Bearer ${token}` }}
|
|
39
|
+
...
|
|
40
|
+
/>
|
|
27
41
|
```
|
|
28
42
|
|
|
29
|
-
|
|
43
|
+
### Option B: You control session creation
|
|
30
44
|
|
|
31
45
|
```tsx
|
|
32
46
|
import { FlonkKYCWidget } from '@flonkid/kyc';
|
|
33
47
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
}
|
|
48
|
+
// 1. Create session on your backend first
|
|
49
|
+
const { sessionId, embedToken } = await fetch('/api/kyc/create-session', {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
body: JSON.stringify({ email: user.email }),
|
|
52
|
+
}).then(r => r.json());
|
|
53
|
+
|
|
54
|
+
// 2. Pass credentials to widget
|
|
55
|
+
<FlonkKYCWidget
|
|
56
|
+
sessionId={sessionId}
|
|
57
|
+
embedToken={embedToken}
|
|
58
|
+
lang="de"
|
|
59
|
+
onSuccess={(result) => console.log('Verified:', result)}
|
|
60
|
+
onError={(error) => console.error(error)}
|
|
61
|
+
onCancel={() => console.log('Cancelled')}
|
|
62
|
+
/>
|
|
43
63
|
```
|
|
44
64
|
|
|
45
65
|
### Props
|
|
46
66
|
|
|
47
67
|
| Prop | Type | Description |
|
|
48
68
|
|------|------|-------------|
|
|
49
|
-
| `
|
|
50
|
-
| `
|
|
51
|
-
| `
|
|
52
|
-
| `
|
|
69
|
+
| `serverUrl` | `string` | Your backend endpoint — SDK auto-creates session |
|
|
70
|
+
| `sessionId` | `string` | Pre-created session ID (Option B) |
|
|
71
|
+
| `embedToken` | `string` | JWT token from your backend (Option B) |
|
|
72
|
+
| `requestHeaders` | `Record<string, string>` | Extra headers for serverUrl (e.g. JWT auth) |
|
|
73
|
+
| `clientMetadata` | `Record<string, unknown>` | Custom data passed to session |
|
|
53
74
|
| `lang` | `'en' \| 'de' \| 'uk'` | Widget language |
|
|
54
75
|
| `onSuccess` | `(result) => void` | Verification completed |
|
|
55
76
|
| `onError` | `(error) => void` | Error occurred |
|
|
@@ -57,6 +78,26 @@ function App() {
|
|
|
57
78
|
| `onReady` | `() => void` | Widget loaded |
|
|
58
79
|
| `autoOpen` | `boolean` | Open on mount (default: `true`) |
|
|
59
80
|
|
|
81
|
+
## Imperative API (non-React)
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
import { FlonkKYC } from '@flonkid/kyc';
|
|
85
|
+
|
|
86
|
+
const kyc = new FlonkKYC();
|
|
87
|
+
|
|
88
|
+
const widget = await kyc.init({
|
|
89
|
+
serverUrl: '/api/kyc/create-session',
|
|
90
|
+
clientMetadata: { email: 'user@example.com' },
|
|
91
|
+
lang: 'de',
|
|
92
|
+
onSuccess: (result) => console.log('Verified:', result),
|
|
93
|
+
onError: (error) => console.error(error),
|
|
94
|
+
onCancel: () => console.log('Cancelled'),
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Cleanup
|
|
98
|
+
widget.destroy();
|
|
99
|
+
```
|
|
100
|
+
|
|
60
101
|
## Server — Node.js
|
|
61
102
|
|
|
62
103
|
```typescript
|
|
@@ -65,11 +106,14 @@ import { FlonkKYCServer } from '@flonkid/kyc/server';
|
|
|
65
106
|
const flonk = new FlonkKYCServer({ secretKey: 'sk_live_...' });
|
|
66
107
|
|
|
67
108
|
// Create session
|
|
68
|
-
const session = await flonk.
|
|
69
|
-
clientMetadata: { userId: 'user_123' },
|
|
109
|
+
const session = await flonk.createSession({
|
|
110
|
+
clientMetadata: { email: 'user@example.com', userId: 'user_123' },
|
|
111
|
+
expiryMinutes: 30,
|
|
112
|
+
language: 'de',
|
|
70
113
|
});
|
|
114
|
+
// → { id, embedToken, status, expiresAt, widgetUrl, qrCodeUrl }
|
|
71
115
|
|
|
72
|
-
// Verify webhook
|
|
116
|
+
// Verify webhook
|
|
73
117
|
const event = flonk.webhooks.constructEvent(rawBody, signature, secret);
|
|
74
118
|
```
|
|
75
119
|
|
|
@@ -78,7 +122,7 @@ const event = flonk.webhooks.constructEvent(rawBody, signature, secret);
|
|
|
78
122
|
| Event | Description |
|
|
79
123
|
|-------|-------------|
|
|
80
124
|
| `verification.completed` | AI verification finished |
|
|
81
|
-
| `verification.status_changed` | Admin changed status |
|
|
125
|
+
| `verification.status_changed` | Admin changed status (approved/rejected) |
|
|
82
126
|
| `verification.updated` | Admin edited verification data |
|
|
83
127
|
|
|
84
128
|
```typescript
|
|
@@ -86,13 +130,13 @@ const event = flonk.webhooks.constructEvent(rawBody, signature, secret);
|
|
|
86
130
|
|
|
87
131
|
switch (event.type) {
|
|
88
132
|
case 'verification.completed':
|
|
89
|
-
|
|
133
|
+
console.log('Extracted:', event.data.object.extracted_data);
|
|
90
134
|
break;
|
|
91
135
|
case 'verification.status_changed':
|
|
92
|
-
|
|
136
|
+
console.log('New status:', event.data.object.status);
|
|
93
137
|
break;
|
|
94
138
|
case 'verification.updated':
|
|
95
|
-
|
|
139
|
+
console.log('Updated by:', event.data.object.updated_by);
|
|
96
140
|
break;
|
|
97
141
|
}
|
|
98
142
|
```
|
|
@@ -100,9 +144,9 @@ switch (event.type) {
|
|
|
100
144
|
## Links
|
|
101
145
|
|
|
102
146
|
- [Full Documentation](https://docs.flonk.id)
|
|
103
|
-
- [
|
|
147
|
+
- [Integration Guide](https://docs.flonk.id/docs/integration-frontend-backend)
|
|
104
148
|
- [Webhook Guide](https://docs.flonk.id/docs/webhooks)
|
|
105
|
-
- [
|
|
149
|
+
- [Dashboard](https://dashboard.flonk.id)
|
|
106
150
|
|
|
107
151
|
## License
|
|
108
152
|
|
package/dist/index.cjs
CHANGED
|
@@ -121,11 +121,12 @@ function validateServerUrl(url) {
|
|
|
121
121
|
throw new Error(`Invalid serverUrl: ${url}`);
|
|
122
122
|
}
|
|
123
123
|
}
|
|
124
|
-
async function fetchSessionFromServer(serverUrl, clientMetadata) {
|
|
124
|
+
async function fetchSessionFromServer(serverUrl, clientMetadata, requestHeaders) {
|
|
125
125
|
validateServerUrl(serverUrl);
|
|
126
126
|
const res = await fetch(serverUrl, {
|
|
127
127
|
method: "POST",
|
|
128
|
-
headers: { "Content-Type": "application/json" },
|
|
128
|
+
headers: { "Content-Type": "application/json", ...requestHeaders },
|
|
129
|
+
credentials: "include",
|
|
129
130
|
body: JSON.stringify({ clientMetadata })
|
|
130
131
|
});
|
|
131
132
|
if (!res.ok) {
|
|
@@ -775,7 +776,8 @@ var FlonkKYC = class {
|
|
|
775
776
|
try {
|
|
776
777
|
const { sessionId, embedToken } = await fetchSessionFromServer(
|
|
777
778
|
config.serverUrl,
|
|
778
|
-
config.clientMetadata
|
|
779
|
+
config.clientMetadata,
|
|
780
|
+
config.requestHeaders
|
|
779
781
|
);
|
|
780
782
|
loader.destroy();
|
|
781
783
|
return this.initWithEmbedToken({ ...config, sessionId, embedToken });
|
|
@@ -984,6 +986,7 @@ function FlonkKYCWidget({
|
|
|
984
986
|
lang,
|
|
985
987
|
overlayColor,
|
|
986
988
|
allowManualUpload,
|
|
989
|
+
requestHeaders,
|
|
987
990
|
onSuccess,
|
|
988
991
|
onError,
|
|
989
992
|
onCancel,
|
|
@@ -991,50 +994,45 @@ function FlonkKYCWidget({
|
|
|
991
994
|
}) {
|
|
992
995
|
const mountRef = react.useRef(null);
|
|
993
996
|
const widgetRef = react.useRef(null);
|
|
994
|
-
const destroyedRef = react.useRef(false);
|
|
995
|
-
const initPromiseRef = react.useRef(null);
|
|
996
997
|
const callbacksRef = react.useRef({ onSuccess, onError, onCancel, onReady });
|
|
997
998
|
callbacksRef.current = { onSuccess, onError, onCancel, onReady };
|
|
998
999
|
const sdk = react.useMemo(() => new FlonkKYC({ widgetUrl, apiBase }), [widgetUrl, apiBase]);
|
|
1000
|
+
const generationRef = react.useRef(0);
|
|
999
1001
|
react.useEffect(() => {
|
|
1000
1002
|
if (!autoOpen) return;
|
|
1001
|
-
const
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
try {
|
|
1023
|
-
const instance = await sdk.init(config);
|
|
1024
|
-
if (destroyedRef.current) {
|
|
1003
|
+
const thisGeneration = ++generationRef.current;
|
|
1004
|
+
const config = {
|
|
1005
|
+
publishableKey,
|
|
1006
|
+
serverUrl,
|
|
1007
|
+
sessionId,
|
|
1008
|
+
embedToken,
|
|
1009
|
+
clientMetadata,
|
|
1010
|
+
lang,
|
|
1011
|
+
overlayColor,
|
|
1012
|
+
allowManualUpload,
|
|
1013
|
+
requestHeaders,
|
|
1014
|
+
mount: mountRef.current || void 0,
|
|
1015
|
+
onSuccess: (r) => callbacksRef.current.onSuccess?.(r),
|
|
1016
|
+
onError: (e) => callbacksRef.current.onError?.(e),
|
|
1017
|
+
onCancel: () => callbacksRef.current.onCancel?.(),
|
|
1018
|
+
onReady: () => callbacksRef.current.onReady?.()
|
|
1019
|
+
};
|
|
1020
|
+
const timer = setTimeout(() => {
|
|
1021
|
+
if (generationRef.current !== thisGeneration) return;
|
|
1022
|
+
sdk.init(config).then((instance) => {
|
|
1023
|
+
if (generationRef.current !== thisGeneration) {
|
|
1025
1024
|
instance.destroy();
|
|
1026
1025
|
} else {
|
|
1027
1026
|
widgetRef.current = instance;
|
|
1028
1027
|
}
|
|
1029
|
-
}
|
|
1030
|
-
if (
|
|
1028
|
+
}).catch((err) => {
|
|
1029
|
+
if (generationRef.current === thisGeneration) {
|
|
1031
1030
|
callbacksRef.current.onError?.(err.message);
|
|
1032
1031
|
}
|
|
1033
|
-
}
|
|
1034
|
-
};
|
|
1035
|
-
initPromiseRef.current = run();
|
|
1032
|
+
});
|
|
1033
|
+
}, 0);
|
|
1036
1034
|
return () => {
|
|
1037
|
-
|
|
1035
|
+
clearTimeout(timer);
|
|
1038
1036
|
widgetRef.current?.destroy();
|
|
1039
1037
|
widgetRef.current = null;
|
|
1040
1038
|
};
|