@flonkid/kyc 1.6.1 → 1.8.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 +175 -169
- package/dist/index.cjs +319 -363
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +57 -10
- package/dist/index.d.ts +57 -10
- package/dist/index.js +319 -364
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +21 -46
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +21 -46
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +9 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { useRef, useMemo, useEffect } from 'react';
|
|
2
|
-
|
|
3
|
-
var __defProp = Object.defineProperty;
|
|
4
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
|
-
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
6
|
-
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
2
|
+
import { jsx } from 'react/jsx-runtime';
|
|
7
3
|
|
|
8
4
|
// src/shared/constants.ts
|
|
9
|
-
var SDK_VERSION = "1.
|
|
5
|
+
var SDK_VERSION = "1.8.0";
|
|
10
6
|
var DEFAULT_WIDGET_URL = "https://widget.flonk.id";
|
|
11
7
|
var DEFAULT_API_BASE = "https://api.flonk.id/v1";
|
|
12
8
|
var WIDGET_EVENTS = {
|
|
@@ -17,43 +13,35 @@ var WIDGET_EVENTS = {
|
|
|
17
13
|
};
|
|
18
14
|
|
|
19
15
|
// src/shared/errors.ts
|
|
20
|
-
var
|
|
16
|
+
var FlonkError = class extends Error {
|
|
21
17
|
constructor(message, code, statusCode) {
|
|
22
18
|
super(message);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
this.code = code, this.statusCode = statusCode;
|
|
19
|
+
this.code = code;
|
|
20
|
+
this.statusCode = statusCode;
|
|
26
21
|
this.name = "FlonkError";
|
|
27
22
|
}
|
|
28
23
|
};
|
|
29
|
-
|
|
30
|
-
var FlonkError = _FlonkError;
|
|
31
|
-
var _FlonkValidationError = class _FlonkValidationError extends FlonkError {
|
|
24
|
+
var FlonkValidationError = class extends FlonkError {
|
|
32
25
|
constructor(message) {
|
|
33
26
|
super(message, "validation_error", 400);
|
|
34
27
|
this.name = "FlonkValidationError";
|
|
35
28
|
}
|
|
36
29
|
};
|
|
37
|
-
__name(_FlonkValidationError, "FlonkValidationError");
|
|
38
|
-
var FlonkValidationError = _FlonkValidationError;
|
|
39
30
|
|
|
40
31
|
// src/browser/utils.ts
|
|
41
32
|
function getOrigin(url) {
|
|
42
33
|
try {
|
|
43
34
|
return new URL(url).origin;
|
|
44
35
|
} catch {
|
|
45
|
-
return
|
|
36
|
+
return "null";
|
|
46
37
|
}
|
|
47
38
|
}
|
|
48
|
-
__name(getOrigin, "getOrigin");
|
|
49
39
|
function isDesktop() {
|
|
50
40
|
return window.innerWidth >= 1024 && !("ontouchstart" in window || navigator.maxTouchPoints > 0);
|
|
51
41
|
}
|
|
52
|
-
__name(isDesktop, "isDesktop");
|
|
53
42
|
function setStyles(el, styles) {
|
|
54
43
|
Object.assign(el.style, styles);
|
|
55
44
|
}
|
|
56
|
-
__name(setStyles, "setStyles");
|
|
57
45
|
function createEl(tag, styles, attrs) {
|
|
58
46
|
const el = document.createElement(tag);
|
|
59
47
|
if (styles) setStyles(el, styles);
|
|
@@ -62,15 +50,13 @@ function createEl(tag, styles, attrs) {
|
|
|
62
50
|
}
|
|
63
51
|
return el;
|
|
64
52
|
}
|
|
65
|
-
__name(createEl, "createEl");
|
|
66
53
|
function debounce(fn, ms) {
|
|
67
54
|
let timer;
|
|
68
|
-
return (...args) => {
|
|
55
|
+
return ((...args) => {
|
|
69
56
|
clearTimeout(timer);
|
|
70
57
|
timer = setTimeout(() => fn(...args), ms);
|
|
71
|
-
};
|
|
58
|
+
});
|
|
72
59
|
}
|
|
73
|
-
__name(debounce, "debounce");
|
|
74
60
|
function generateSecondaryColor(hex) {
|
|
75
61
|
try {
|
|
76
62
|
const h = hex.replace("#", "");
|
|
@@ -78,21 +64,33 @@ function generateSecondaryColor(hex) {
|
|
|
78
64
|
const g = parseInt(h.substring(2, 4), 16);
|
|
79
65
|
const b = parseInt(h.substring(4, 6), 16);
|
|
80
66
|
const f = 0.6;
|
|
81
|
-
const toHex =
|
|
67
|
+
const toHex = (n) => {
|
|
82
68
|
const s = n.toString(16);
|
|
83
69
|
return s.length === 1 ? "0" + s : s;
|
|
84
|
-
}
|
|
70
|
+
};
|
|
85
71
|
return "#" + toHex(Math.round(r + (255 - r) * f)) + toHex(Math.round(g + (255 - g) * f)) + toHex(Math.round(b + (255 - b) * f));
|
|
86
72
|
} catch {
|
|
87
73
|
return "#93c5fd";
|
|
88
74
|
}
|
|
89
75
|
}
|
|
90
|
-
|
|
76
|
+
var DEFAULT_FETCH_TIMEOUT_MS = 2e4;
|
|
77
|
+
async function fetchWithTimeout(url, init = {}, timeoutMs = DEFAULT_FETCH_TIMEOUT_MS) {
|
|
78
|
+
const controller = new AbortController();
|
|
79
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
80
|
+
try {
|
|
81
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
82
|
+
} catch (err) {
|
|
83
|
+
if (err?.name === "AbortError") {
|
|
84
|
+
throw new Error(`Request timed out after ${timeoutMs}ms: ${url}`);
|
|
85
|
+
}
|
|
86
|
+
throw err;
|
|
87
|
+
} finally {
|
|
88
|
+
clearTimeout(timer);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
91
|
async function fetchWidgetToken(pk, apiBase) {
|
|
92
|
-
const res = await
|
|
93
|
-
headers: {
|
|
94
|
-
"x-kyc-pk": pk
|
|
95
|
-
},
|
|
92
|
+
const res = await fetchWithTimeout(`${apiBase}/public/widget-token`, {
|
|
93
|
+
headers: { "x-kyc-pk": pk },
|
|
96
94
|
credentials: "include"
|
|
97
95
|
});
|
|
98
96
|
if (!res.ok) {
|
|
@@ -106,51 +104,66 @@ async function fetchWidgetToken(pk, apiBase) {
|
|
|
106
104
|
}
|
|
107
105
|
return res.json();
|
|
108
106
|
}
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
var BRANDING_CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
108
|
+
var brandingCache = /* @__PURE__ */ new Map();
|
|
109
|
+
function brandingCacheKey(opts) {
|
|
110
|
+
if (opts.pk) return `pk:${opts.pk}`;
|
|
111
|
+
if (opts.sessionId) return `sid:${opts.sessionId}`;
|
|
112
|
+
if (opts.clientId) return `cid:${opts.clientId}`;
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
async function requestDesignTokens(apiBase, opts) {
|
|
111
116
|
const params = [];
|
|
112
117
|
if (opts.sessionId) params.push(`sessionId=${encodeURIComponent(opts.sessionId)}`);
|
|
113
118
|
else if (opts.clientId) params.push(`clientId=${encodeURIComponent(opts.clientId)}`);
|
|
114
119
|
const url = `${apiBase}/public/design-tokens${params.length ? "?" + params.join("&") : ""}`;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
120
|
+
const res = await fetchWithTimeout(
|
|
121
|
+
url,
|
|
122
|
+
{ headers: opts.pk ? { "x-kyc-pk": opts.pk } : {}, credentials: "omit" },
|
|
123
|
+
8e3
|
|
124
|
+
);
|
|
125
|
+
return res.ok ? res.json() : null;
|
|
126
|
+
}
|
|
127
|
+
async function fetchDesignTokens(apiBase, opts) {
|
|
128
|
+
const key = brandingCacheKey(opts);
|
|
129
|
+
if (!key) return null;
|
|
130
|
+
const now = Date.now();
|
|
131
|
+
const cached = brandingCache.get(key);
|
|
132
|
+
if (cached && cached.expiresAt > now) {
|
|
133
|
+
return cached.promise;
|
|
125
134
|
}
|
|
135
|
+
const promise = requestDesignTokens(apiBase, opts).catch(() => null);
|
|
136
|
+
brandingCache.set(key, { promise, expiresAt: now + BRANDING_CACHE_TTL_MS });
|
|
137
|
+
promise.then((tokens) => {
|
|
138
|
+
if (tokens == null) brandingCache.delete(key);
|
|
139
|
+
});
|
|
140
|
+
return promise;
|
|
141
|
+
}
|
|
142
|
+
function preloadDesignTokens(apiBase, opts) {
|
|
143
|
+
return fetchDesignTokens(apiBase, opts);
|
|
126
144
|
}
|
|
127
|
-
__name(fetchDesignTokens, "fetchDesignTokens");
|
|
128
145
|
function validateServerUrl(url) {
|
|
129
146
|
if (url.startsWith("/")) return;
|
|
130
147
|
try {
|
|
131
148
|
const parsed = new URL(url);
|
|
132
149
|
const isLocalhost = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
133
150
|
if (parsed.protocol !== "https:" && !isLocalhost) {
|
|
134
|
-
throw new Error(
|
|
151
|
+
throw new Error(
|
|
152
|
+
`serverUrl must use HTTPS in production. Got: ${parsed.protocol}//. Use HTTPS ('https://api.myapp.com/...') or a relative path ('/api/...')`
|
|
153
|
+
);
|
|
135
154
|
}
|
|
136
155
|
} catch (e) {
|
|
137
156
|
if (e.message.includes("serverUrl must use HTTPS")) throw e;
|
|
138
157
|
throw new Error(`Invalid serverUrl: ${url}`);
|
|
139
158
|
}
|
|
140
159
|
}
|
|
141
|
-
__name(validateServerUrl, "validateServerUrl");
|
|
142
160
|
async function fetchSessionFromServer(serverUrl, clientMetadata, requestHeaders) {
|
|
143
161
|
validateServerUrl(serverUrl);
|
|
144
|
-
const res = await
|
|
162
|
+
const res = await fetchWithTimeout(serverUrl, {
|
|
145
163
|
method: "POST",
|
|
146
|
-
headers: {
|
|
147
|
-
"Content-Type": "application/json",
|
|
148
|
-
...requestHeaders
|
|
149
|
-
},
|
|
164
|
+
headers: { "Content-Type": "application/json", ...requestHeaders },
|
|
150
165
|
credentials: "include",
|
|
151
|
-
body: JSON.stringify({
|
|
152
|
-
clientMetadata
|
|
153
|
-
})
|
|
166
|
+
body: JSON.stringify({ clientMetadata })
|
|
154
167
|
});
|
|
155
168
|
if (!res.ok) {
|
|
156
169
|
let message = `Session request failed (${res.status})`;
|
|
@@ -164,9 +177,8 @@ async function fetchSessionFromServer(serverUrl, clientMetadata, requestHeaders)
|
|
|
164
177
|
}
|
|
165
178
|
return res.json();
|
|
166
179
|
}
|
|
167
|
-
__name(fetchSessionFromServer, "fetchSessionFromServer");
|
|
168
180
|
async function fetchPublicSession(apiBase, sessionId, embedToken) {
|
|
169
|
-
const res = await
|
|
181
|
+
const res = await fetchWithTimeout(`${apiBase}/public/session/${sessionId}`, {
|
|
170
182
|
headers: {
|
|
171
183
|
"Content-Type": "application/json",
|
|
172
184
|
"Authorization": `Bearer ${embedToken}`
|
|
@@ -183,13 +195,10 @@ async function fetchPublicSession(apiBase, sessionId, embedToken) {
|
|
|
183
195
|
}
|
|
184
196
|
return res.json();
|
|
185
197
|
}
|
|
186
|
-
__name(fetchPublicSession, "fetchPublicSession");
|
|
187
198
|
async function exchangeSessionForToken(apiBase, sessionId) {
|
|
188
|
-
const res = await
|
|
199
|
+
const res = await fetchWithTimeout(`${apiBase}/public/session/${sessionId}/token`, {
|
|
189
200
|
method: "POST",
|
|
190
|
-
headers: {
|
|
191
|
-
"Content-Type": "application/json"
|
|
192
|
-
}
|
|
201
|
+
headers: { "Content-Type": "application/json" }
|
|
193
202
|
});
|
|
194
203
|
if (!res.ok) {
|
|
195
204
|
let message = `Token exchange failed (${res.status})`;
|
|
@@ -202,33 +211,36 @@ async function exchangeSessionForToken(apiBase, sessionId) {
|
|
|
202
211
|
}
|
|
203
212
|
return res.json();
|
|
204
213
|
}
|
|
205
|
-
__name(exchangeSessionForToken, "exchangeSessionForToken");
|
|
206
214
|
|
|
207
215
|
// src/browser/iframe-manager.ts
|
|
208
216
|
function createIframe(src) {
|
|
209
217
|
const d = isDesktop();
|
|
210
|
-
const iframe = createEl(
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
218
|
+
const iframe = createEl(
|
|
219
|
+
"iframe",
|
|
220
|
+
{
|
|
221
|
+
border: "0",
|
|
222
|
+
width: window.innerWidth + "px",
|
|
223
|
+
height: window.innerHeight + "px",
|
|
224
|
+
position: "fixed",
|
|
225
|
+
top: "0",
|
|
226
|
+
left: "0",
|
|
227
|
+
zIndex: "9999",
|
|
228
|
+
background: "transparent",
|
|
229
|
+
backgroundColor: "transparent",
|
|
230
|
+
opacity: "0",
|
|
231
|
+
visibility: "hidden",
|
|
232
|
+
borderRadius: d ? "0" : "",
|
|
233
|
+
boxShadow: d ? "none" : "",
|
|
234
|
+
colorScheme: "normal"
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
src,
|
|
238
|
+
allow: "camera;microphone;clipboard-read;clipboard-write",
|
|
239
|
+
sandbox: "allow-scripts allow-forms allow-same-origin allow-popups",
|
|
240
|
+
"aria-label": "KYC Verification",
|
|
241
|
+
allowtransparency: "true"
|
|
242
|
+
}
|
|
243
|
+
);
|
|
232
244
|
try {
|
|
233
245
|
iframe.style.setProperty("background", "transparent", "important");
|
|
234
246
|
iframe.style.setProperty("background-color", "transparent", "important");
|
|
@@ -237,24 +249,21 @@ function createIframe(src) {
|
|
|
237
249
|
}
|
|
238
250
|
return iframe;
|
|
239
251
|
}
|
|
240
|
-
__name(createIframe, "createIframe");
|
|
241
252
|
function adjustZIndex(loader, iframe) {
|
|
242
253
|
if (!isDesktop()) return;
|
|
243
254
|
const all = Array.from(document.querySelectorAll("*"));
|
|
244
|
-
const maxZ = Math.max(
|
|
255
|
+
const maxZ = Math.max(
|
|
256
|
+
...all.map((el) => parseInt(getComputedStyle(el).zIndex) || 0).filter((z) => z < 999999)
|
|
257
|
+
);
|
|
245
258
|
if (maxZ > 9998) {
|
|
246
259
|
loader.style.zIndex = String(maxZ + 1);
|
|
247
260
|
iframe.style.zIndex = String(maxZ + 2);
|
|
248
261
|
}
|
|
249
262
|
}
|
|
250
|
-
__name(adjustZIndex, "adjustZIndex");
|
|
251
263
|
function transitionLoaderToIframe(loader, iframe, onDone) {
|
|
252
264
|
const d = isDesktop();
|
|
253
265
|
const dur = d ? 300 : 500;
|
|
254
|
-
setStyles(iframe, {
|
|
255
|
-
opacity: "0",
|
|
256
|
-
visibility: "hidden"
|
|
257
|
-
});
|
|
266
|
+
setStyles(iframe, { opacity: "0", visibility: "hidden" });
|
|
258
267
|
const card = loader.querySelector("div");
|
|
259
268
|
if (card) {
|
|
260
269
|
setStyles(card, {
|
|
@@ -272,28 +281,12 @@ function transitionLoaderToIframe(loader, iframe, onDone) {
|
|
|
272
281
|
});
|
|
273
282
|
}, dur);
|
|
274
283
|
}
|
|
275
|
-
__name(transitionLoaderToIframe, "transitionLoaderToIframe");
|
|
276
284
|
|
|
277
285
|
// src/browser/loader.ts
|
|
278
286
|
var LOADER_I18N = {
|
|
279
|
-
en: {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
errorTitle: "Something went wrong",
|
|
283
|
-
close: "Close"
|
|
284
|
-
},
|
|
285
|
-
de: {
|
|
286
|
-
title: "Initialisierung...",
|
|
287
|
-
subtitle: "KYC-Widget wird geladen",
|
|
288
|
-
errorTitle: "Ein Fehler ist aufgetreten",
|
|
289
|
-
close: "Schlie\xDFen"
|
|
290
|
-
},
|
|
291
|
-
uk: {
|
|
292
|
-
title: "\u0406\u043D\u0456\u0446\u0456\u0430\u043B\u0456\u0437\u0430\u0446\u0456\u044F...",
|
|
293
|
-
subtitle: "\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F KYC-\u0432\u0456\u0434\u0436\u0435\u0442\u0430",
|
|
294
|
-
errorTitle: "\u0429\u043E\u0441\u044C \u043F\u0456\u0448\u043B\u043E \u043D\u0435 \u0442\u0430\u043A",
|
|
295
|
-
close: "\u0417\u0430\u043A\u0440\u0438\u0442\u0438"
|
|
296
|
-
}
|
|
287
|
+
en: { title: "Initializing...", subtitle: "Loading KYC widget", errorTitle: "Something went wrong", close: "Close" },
|
|
288
|
+
de: { title: "Initialisierung...", subtitle: "KYC-Widget wird geladen", errorTitle: "Ein Fehler ist aufgetreten", close: "Schlie\xDFen" },
|
|
289
|
+
uk: { title: "\u0406\u043D\u0456\u0446\u0456\u0430\u043B\u0456\u0437\u0430\u0446\u0456\u044F...", subtitle: "\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0435\u043D\u043D\u044F KYC-\u0432\u0456\u0434\u0436\u0435\u0442\u0430", errorTitle: "\u0429\u043E\u0441\u044C \u043F\u0456\u0448\u043B\u043E \u043D\u0435 \u0442\u0430\u043A", close: "\u0417\u0430\u043A\u0440\u0438\u0442\u0438" }
|
|
297
290
|
};
|
|
298
291
|
var KEYFRAMES = `
|
|
299
292
|
@keyframes kycspin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}
|
|
@@ -301,11 +294,11 @@ var KEYFRAMES = `
|
|
|
301
294
|
@keyframes kycprogress{0%{transform:translateX(-100%)}50%{transform:translateX(0%)}100%{transform:translateX(250%)}}
|
|
302
295
|
`.trim();
|
|
303
296
|
var styleInjected = false;
|
|
304
|
-
var
|
|
297
|
+
var Loader = class {
|
|
305
298
|
constructor() {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
299
|
+
this.overlay = null;
|
|
300
|
+
this.cleanup = null;
|
|
301
|
+
this.origBodyStyles = null;
|
|
309
302
|
}
|
|
310
303
|
show(primaryColor, lang) {
|
|
311
304
|
const color = primaryColor || "#15BA68";
|
|
@@ -384,64 +377,23 @@ var _Loader = class _Loader {
|
|
|
384
377
|
"stroke-dasharray": "62.8",
|
|
385
378
|
"stroke-dashoffset": "15.7"
|
|
386
379
|
})) fg.setAttribute(k, v);
|
|
387
|
-
setStyles(fg, {
|
|
388
|
-
transformOrigin: "center",
|
|
389
|
-
animation: "kycdash 1.5s ease-in-out infinite"
|
|
390
|
-
});
|
|
380
|
+
setStyles(fg, { transformOrigin: "center", animation: "kycdash 1.5s ease-in-out infinite" });
|
|
391
381
|
svg.append(bg, fg);
|
|
392
382
|
wrap.appendChild(svg);
|
|
393
383
|
const font = 'Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif';
|
|
394
|
-
const textBox = createEl("div", {
|
|
395
|
-
|
|
396
|
-
});
|
|
397
|
-
const title = createEl("h3", {
|
|
398
|
-
fontFamily: font,
|
|
399
|
-
fontWeight: "600",
|
|
400
|
-
fontSize: "18px",
|
|
401
|
-
lineHeight: "1.3",
|
|
402
|
-
color: "#1F2937",
|
|
403
|
-
margin: "0 0 4px 0"
|
|
404
|
-
});
|
|
384
|
+
const textBox = createEl("div", { textAlign: "center" });
|
|
385
|
+
const title = createEl("h3", { fontFamily: font, fontWeight: "600", fontSize: "18px", lineHeight: "1.3", color: "#1F2937", margin: "0 0 4px 0" });
|
|
405
386
|
title.textContent = strings.title;
|
|
406
|
-
const subtitle = createEl("p", {
|
|
407
|
-
fontFamily: font,
|
|
408
|
-
fontWeight: "400",
|
|
409
|
-
fontSize: "13px",
|
|
410
|
-
lineHeight: "1.4",
|
|
411
|
-
color: "rgba(31,41,55,0.7)",
|
|
412
|
-
margin: "0"
|
|
413
|
-
});
|
|
387
|
+
const subtitle = createEl("p", { fontFamily: font, fontWeight: "400", fontSize: "13px", lineHeight: "1.4", color: "rgba(31,41,55,0.7)", margin: "0" });
|
|
414
388
|
subtitle.textContent = strings.subtitle;
|
|
415
389
|
textBox.append(title, subtitle);
|
|
416
|
-
const track = createEl("div", {
|
|
417
|
-
|
|
418
|
-
maxWidth: "240px",
|
|
419
|
-
height: "3px",
|
|
420
|
-
backgroundColor: color + "1A",
|
|
421
|
-
borderRadius: "2px",
|
|
422
|
-
overflow: "hidden"
|
|
423
|
-
});
|
|
424
|
-
const bar = createEl("div", {
|
|
425
|
-
width: "40%",
|
|
426
|
-
height: "100%",
|
|
427
|
-
backgroundColor: color,
|
|
428
|
-
borderRadius: "2px",
|
|
429
|
-
transform: "translateX(-100%)",
|
|
430
|
-
animation: "kycprogress 2000ms ease-in-out infinite"
|
|
431
|
-
});
|
|
390
|
+
const track = createEl("div", { width: "100%", maxWidth: "240px", height: "3px", backgroundColor: color + "1A", borderRadius: "2px", overflow: "hidden" });
|
|
391
|
+
const bar = createEl("div", { width: "40%", height: "100%", backgroundColor: color, borderRadius: "2px", transform: "translateX(-100%)", animation: "kycprogress 2000ms ease-in-out infinite" });
|
|
432
392
|
track.appendChild(bar);
|
|
433
393
|
card.append(wrap, textBox, track);
|
|
434
394
|
overlay.appendChild(card);
|
|
435
|
-
this.origBodyStyles = {
|
|
436
|
-
|
|
437
|
-
position: document.body.style.position
|
|
438
|
-
};
|
|
439
|
-
setStyles(document.body, {
|
|
440
|
-
overflow: "hidden",
|
|
441
|
-
position: "fixed",
|
|
442
|
-
width: "100%",
|
|
443
|
-
height: "100%"
|
|
444
|
-
});
|
|
395
|
+
this.origBodyStyles = { overflow: document.body.style.overflow, position: document.body.style.position };
|
|
396
|
+
setStyles(document.body, { overflow: "hidden", position: "fixed", width: "100%", height: "100%" });
|
|
445
397
|
document.body.appendChild(overlay);
|
|
446
398
|
let prevW = window.innerWidth;
|
|
447
399
|
let prevH = window.innerHeight;
|
|
@@ -449,10 +401,7 @@ var _Loader = class _Loader {
|
|
|
449
401
|
const w = window.innerWidth;
|
|
450
402
|
const h = window.innerHeight;
|
|
451
403
|
if (Math.abs(w - prevW) > 1 || Math.abs(h - prevH) > 1) {
|
|
452
|
-
setStyles(overlay, {
|
|
453
|
-
width: w + "px",
|
|
454
|
-
height: h + "px"
|
|
455
|
-
});
|
|
404
|
+
setStyles(overlay, { width: w + "px", height: h + "px" });
|
|
456
405
|
prevW = w;
|
|
457
406
|
prevH = h;
|
|
458
407
|
}
|
|
@@ -462,11 +411,7 @@ var _Loader = class _Loader {
|
|
|
462
411
|
this.cleanup = () => {
|
|
463
412
|
window.removeEventListener("resize", onResize);
|
|
464
413
|
if (this.origBodyStyles) {
|
|
465
|
-
setStyles(document.body, {
|
|
466
|
-
...this.origBodyStyles,
|
|
467
|
-
width: "",
|
|
468
|
-
height: ""
|
|
469
|
-
});
|
|
414
|
+
setStyles(document.body, { ...this.origBodyStyles, width: "", height: "" });
|
|
470
415
|
}
|
|
471
416
|
};
|
|
472
417
|
return overlay;
|
|
@@ -586,25 +531,20 @@ var _Loader = class _Loader {
|
|
|
586
531
|
this.cleanup = null;
|
|
587
532
|
}
|
|
588
533
|
};
|
|
589
|
-
__name(_Loader, "Loader");
|
|
590
|
-
var Loader = _Loader;
|
|
591
534
|
|
|
592
535
|
// src/browser/message-handler.ts
|
|
593
|
-
var
|
|
536
|
+
var MessageHandler = class {
|
|
594
537
|
constructor(iframeSrc, iframe, callbacks) {
|
|
595
|
-
__publicField(this, "iframeSrc");
|
|
596
|
-
__publicField(this, "iframe");
|
|
597
|
-
__publicField(this, "callbacks");
|
|
598
|
-
__publicField(this, "listener", null);
|
|
599
|
-
__publicField(this, "readyListener", null);
|
|
600
|
-
__publicField(this, "completionHandled", false);
|
|
601
538
|
this.iframeSrc = iframeSrc;
|
|
602
539
|
this.iframe = iframe;
|
|
603
540
|
this.callbacks = callbacks;
|
|
541
|
+
this.listener = null;
|
|
542
|
+
this.readyListener = null;
|
|
543
|
+
this.completionHandled = false;
|
|
604
544
|
}
|
|
605
545
|
/**
|
|
606
|
-
|
|
607
|
-
|
|
546
|
+
* Start listening for postMessage events from the widget iframe.
|
|
547
|
+
*/
|
|
608
548
|
listen() {
|
|
609
549
|
const origin = getOrigin(this.iframeSrc);
|
|
610
550
|
this.listener = (e) => {
|
|
@@ -612,34 +552,33 @@ var _MessageHandler = class _MessageHandler {
|
|
|
612
552
|
if (e.source !== this.iframe.contentWindow) return;
|
|
613
553
|
const data = e.data || {};
|
|
614
554
|
const type = data.type;
|
|
615
|
-
if (type === WIDGET_EVENTS.COMPLETE
|
|
555
|
+
if (type === WIDGET_EVENTS.COMPLETE) {
|
|
616
556
|
if (this.completionHandled) return;
|
|
617
557
|
this.completionHandled = true;
|
|
618
|
-
this.callbacks.onSuccess(data.result);
|
|
619
|
-
|
|
620
|
-
} else if (type === WIDGET_EVENTS.CANCEL && this.callbacks.onCancel) {
|
|
558
|
+
this.callbacks.onSuccess?.(data.result);
|
|
559
|
+
} else if (type === WIDGET_EVENTS.CANCEL) {
|
|
621
560
|
if (this.completionHandled) return;
|
|
622
561
|
this.completionHandled = true;
|
|
623
|
-
this.callbacks.onCancel();
|
|
624
|
-
|
|
625
|
-
} else if (type === WIDGET_EVENTS.ERROR && this.callbacks.onError) {
|
|
562
|
+
this.callbacks.onCancel?.();
|
|
563
|
+
} else if (type === WIDGET_EVENTS.ERROR) {
|
|
626
564
|
if (this.completionHandled) return;
|
|
627
565
|
this.completionHandled = true;
|
|
628
|
-
this.callbacks.onError(data.error || "Unknown error");
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
this.callbacks.onReady();
|
|
566
|
+
this.callbacks.onError?.(data.error || "Unknown error");
|
|
567
|
+
} else if (type === WIDGET_EVENTS.READY) {
|
|
568
|
+
this.callbacks.onReady?.();
|
|
632
569
|
}
|
|
633
570
|
};
|
|
634
571
|
window.addEventListener("message", this.listener);
|
|
635
572
|
}
|
|
636
573
|
/**
|
|
637
|
-
|
|
638
|
-
|
|
574
|
+
* Listen for the first READY event, then call the callback once.
|
|
575
|
+
*/
|
|
639
576
|
onReadyOnce(callback) {
|
|
640
577
|
const origin = getOrigin(this.iframeSrc);
|
|
641
578
|
this.readyListener = (e) => {
|
|
642
|
-
if (e.origin !== origin || e.data?.type !== WIDGET_EVENTS.READY)
|
|
579
|
+
if (e.origin !== origin || e.source !== this.iframe.contentWindow || e.data?.type !== WIDGET_EVENTS.READY) {
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
643
582
|
window.removeEventListener("message", this.readyListener);
|
|
644
583
|
this.readyListener = null;
|
|
645
584
|
callback();
|
|
@@ -657,8 +596,6 @@ var _MessageHandler = class _MessageHandler {
|
|
|
657
596
|
}
|
|
658
597
|
}
|
|
659
598
|
};
|
|
660
|
-
__name(_MessageHandler, "MessageHandler");
|
|
661
|
-
var MessageHandler = _MessageHandler;
|
|
662
599
|
|
|
663
600
|
// src/browser/viewport.ts
|
|
664
601
|
function getVV() {
|
|
@@ -670,14 +607,8 @@ function getVV() {
|
|
|
670
607
|
offsetLeft: window.visualViewport.offsetLeft || 0
|
|
671
608
|
};
|
|
672
609
|
}
|
|
673
|
-
return {
|
|
674
|
-
width: window.innerWidth,
|
|
675
|
-
height: window.innerHeight,
|
|
676
|
-
offsetTop: 0,
|
|
677
|
-
offsetLeft: 0
|
|
678
|
-
};
|
|
610
|
+
return { width: window.innerWidth, height: window.innerHeight, offsetTop: 0, offsetLeft: 0 };
|
|
679
611
|
}
|
|
680
|
-
__name(getVV, "getVV");
|
|
681
612
|
function ensureViewportMeta() {
|
|
682
613
|
try {
|
|
683
614
|
const meta = document.querySelector('meta[name="viewport"]');
|
|
@@ -695,42 +626,31 @@ function ensureViewportMeta() {
|
|
|
695
626
|
} catch {
|
|
696
627
|
}
|
|
697
628
|
}
|
|
698
|
-
__name(ensureViewportMeta, "ensureViewportMeta");
|
|
699
629
|
function setupViewportSizing(overlay, iframe) {
|
|
700
630
|
ensureViewportMeta();
|
|
701
631
|
let baselineHeight = 0;
|
|
702
632
|
let desktop = isDesktop();
|
|
703
633
|
let rafId = null;
|
|
704
|
-
const initBaseline =
|
|
634
|
+
const initBaseline = () => {
|
|
705
635
|
const vv = getVV();
|
|
706
636
|
baselineHeight = window.innerHeight || vv.height || document.documentElement.clientHeight || 0;
|
|
707
637
|
desktop = isDesktop();
|
|
708
638
|
if (rafId) cancelAnimationFrame(rafId);
|
|
709
639
|
rafId = requestAnimationFrame(applySize);
|
|
710
|
-
}
|
|
711
|
-
const applySize =
|
|
640
|
+
};
|
|
641
|
+
const applySize = () => {
|
|
712
642
|
try {
|
|
713
643
|
const vv = getVV();
|
|
714
644
|
const inner = window.innerHeight || vv.height;
|
|
715
645
|
const kbThreshold = desktop ? 200 : 150;
|
|
716
646
|
const isKeyboard = inner - vv.height > kbThreshold;
|
|
717
647
|
const height = isKeyboard ? vv.height : baselineHeight || inner;
|
|
718
|
-
const dims = desktop ? {
|
|
719
|
-
top: "0",
|
|
720
|
-
left: "0",
|
|
721
|
-
width: window.innerWidth + "px",
|
|
722
|
-
height: window.innerHeight + "px"
|
|
723
|
-
} : {
|
|
724
|
-
top: vv.offsetTop + "px",
|
|
725
|
-
left: vv.offsetLeft + "px",
|
|
726
|
-
width: vv.width + "px",
|
|
727
|
-
height: height + "px"
|
|
728
|
-
};
|
|
648
|
+
const dims = desktop ? { top: "0", left: "0", width: window.innerWidth + "px", height: window.innerHeight + "px" } : { top: vv.offsetTop + "px", left: vv.offsetLeft + "px", width: vv.width + "px", height: height + "px" };
|
|
729
649
|
if (overlay) setStyles(overlay, dims);
|
|
730
650
|
if (iframe) setStyles(iframe, dims);
|
|
731
651
|
} catch {
|
|
732
652
|
}
|
|
733
|
-
}
|
|
653
|
+
};
|
|
734
654
|
let prevW = window.innerWidth;
|
|
735
655
|
let prevH = window.innerHeight;
|
|
736
656
|
let prevX = 0;
|
|
@@ -739,7 +659,7 @@ function setupViewportSizing(overlay, iframe) {
|
|
|
739
659
|
if (rafId) cancelAnimationFrame(rafId);
|
|
740
660
|
rafId = requestAnimationFrame(applySize);
|
|
741
661
|
}, desktop ? 50 : 150);
|
|
742
|
-
const handleResize =
|
|
662
|
+
const handleResize = () => {
|
|
743
663
|
const vv = getVV();
|
|
744
664
|
const w = vv.width;
|
|
745
665
|
const h = vv.height;
|
|
@@ -758,12 +678,12 @@ function setupViewportSizing(overlay, iframe) {
|
|
|
758
678
|
} else {
|
|
759
679
|
debouncedApply();
|
|
760
680
|
}
|
|
761
|
-
}
|
|
762
|
-
const handleOrientation =
|
|
681
|
+
};
|
|
682
|
+
const handleOrientation = () => {
|
|
763
683
|
initBaseline();
|
|
764
684
|
if (rafId) cancelAnimationFrame(rafId);
|
|
765
685
|
rafId = requestAnimationFrame(applySize);
|
|
766
|
-
}
|
|
686
|
+
};
|
|
767
687
|
initBaseline();
|
|
768
688
|
applySize();
|
|
769
689
|
window.addEventListener("resize", handleResize);
|
|
@@ -785,26 +705,58 @@ function setupViewportSizing(overlay, iframe) {
|
|
|
785
705
|
}
|
|
786
706
|
};
|
|
787
707
|
}
|
|
788
|
-
__name(setupViewportSizing, "setupViewportSizing");
|
|
789
708
|
|
|
790
709
|
// src/browser/index.ts
|
|
791
|
-
var
|
|
710
|
+
var FALLBACK_PRIMARY = "#15BA68";
|
|
711
|
+
var EARLY_COLOR_BUDGET_MS = 800;
|
|
712
|
+
var primaryFrom = (tokens) => tokens?.colors?.primary?.cannabis || FALLBACK_PRIMARY;
|
|
713
|
+
async function showLoaderWithEarlyColor(tokensPromise, lang) {
|
|
714
|
+
const earlyTokens = await Promise.race([
|
|
715
|
+
tokensPromise,
|
|
716
|
+
new Promise((resolve) => setTimeout(() => resolve(null), EARLY_COLOR_BUDGET_MS))
|
|
717
|
+
]);
|
|
718
|
+
const primaryColor = primaryFrom(earlyTokens);
|
|
719
|
+
const loader = new Loader();
|
|
720
|
+
loader.show(primaryColor, lang);
|
|
721
|
+
return { loader, primaryColor };
|
|
722
|
+
}
|
|
723
|
+
var FlonkKYC = class {
|
|
792
724
|
constructor(options = {}) {
|
|
793
|
-
__publicField(this, "widgetUrl");
|
|
794
|
-
__publicField(this, "apiBase");
|
|
795
725
|
this.widgetUrl = (options.widgetUrl || DEFAULT_WIDGET_URL).replace(/\/$/, "");
|
|
796
726
|
this.apiBase = (options.apiBase || DEFAULT_API_BASE).replace(/\/$/, "");
|
|
797
727
|
}
|
|
728
|
+
/**
|
|
729
|
+
* Warm the project's branding (colors) ahead of time so the widget paints the
|
|
730
|
+
* brand color on the first frame, with no branding round-trip at click time.
|
|
731
|
+
*
|
|
732
|
+
* Call it early — on page mount, route enter, or hover of the "verify" button
|
|
733
|
+
* — well before `init()`. The result is cached (module-level, 5-min TTL) and
|
|
734
|
+
* every subsequent `init()`/`open()` for the same key reads from it. Safe to
|
|
735
|
+
* call repeatedly; concurrent calls dedupe. Never throws.
|
|
736
|
+
*
|
|
737
|
+
* @example
|
|
738
|
+
* // in a layout effect, long before the user clicks "Verify"
|
|
739
|
+
* FlonkKYC.preloadBranding({ publishableKey: 'pk_live_...' });
|
|
740
|
+
*/
|
|
741
|
+
static preloadBranding(opts) {
|
|
742
|
+
const apiBase = (opts.apiBase || DEFAULT_API_BASE).replace(/\/$/, "");
|
|
743
|
+
return preloadDesignTokens(apiBase, {
|
|
744
|
+
pk: opts.publishableKey,
|
|
745
|
+
sessionId: opts.sessionId
|
|
746
|
+
}).then(() => void 0);
|
|
747
|
+
}
|
|
798
748
|
// ── Public API ───────────────────────────────────────
|
|
799
749
|
/**
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
750
|
+
* Open the KYC verification widget.
|
|
751
|
+
*
|
|
752
|
+
* Flows (pick one; add `publishableKey` to any for an instant branded loader):
|
|
753
|
+
* 1. `{ serverUrl }` — SDK auto-creates the session via your backend (recommended).
|
|
754
|
+
* 2. `{ sessionId, embedToken }` — you created the session; pass its credentials.
|
|
755
|
+
* 3. `{ sessionId }` — **deprecated**: exchanges the sessionId for an embedToken
|
|
756
|
+
* via an extra round-trip. Prefer flow 2 by returning `embedToken` from your
|
|
757
|
+
* backend alongside `sessionId`.
|
|
758
|
+
* 4. `{ publishableKey }` — client-only; SDK mints a short-lived widget token.
|
|
759
|
+
*/
|
|
808
760
|
async init(config) {
|
|
809
761
|
if (!config) throw new FlonkValidationError("config is required");
|
|
810
762
|
if (config.serverUrl) {
|
|
@@ -818,18 +770,17 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
818
770
|
}
|
|
819
771
|
const pk = config.publishableKey;
|
|
820
772
|
if (!pk || !/^pk_/.test(pk)) {
|
|
821
|
-
throw new FlonkValidationError(
|
|
773
|
+
throw new FlonkValidationError(
|
|
774
|
+
"Provide one of: serverUrl, sessionId + embedToken, or publishableKey (pk_*)"
|
|
775
|
+
);
|
|
822
776
|
}
|
|
823
777
|
return this.initWithPublishableKey(config);
|
|
824
778
|
}
|
|
825
779
|
/**
|
|
826
|
-
|
|
827
|
-
|
|
780
|
+
* Preview mode — no API calls, mock data.
|
|
781
|
+
*/
|
|
828
782
|
preview(config = {}) {
|
|
829
|
-
const colors = config.colors || {
|
|
830
|
-
primaryColor: "#3b82f6",
|
|
831
|
-
secondaryColor: "#93c5fd"
|
|
832
|
-
};
|
|
783
|
+
const colors = config.colors || { primaryColor: "#3b82f6", secondaryColor: "#93c5fd" };
|
|
833
784
|
return this.openWidget({
|
|
834
785
|
mode: "preview",
|
|
835
786
|
isPreview: "true",
|
|
@@ -847,20 +798,17 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
847
798
|
});
|
|
848
799
|
}
|
|
849
800
|
/**
|
|
850
|
-
|
|
851
|
-
|
|
801
|
+
* Embed inline preview in a container (for dashboards).
|
|
802
|
+
*/
|
|
852
803
|
embed(config) {
|
|
853
804
|
if (!config?.container) throw new FlonkValidationError("container is required");
|
|
854
805
|
const container = typeof config.container === "string" ? document.querySelector(config.container) : config.container;
|
|
855
806
|
if (!container) throw new FlonkValidationError("Container element not found");
|
|
856
|
-
let colors = config.colors || {
|
|
857
|
-
primaryColor: "#3b82f6",
|
|
858
|
-
secondaryColor: "#93c5fd"
|
|
859
|
-
};
|
|
807
|
+
let colors = config.colors || { primaryColor: "#3b82f6", secondaryColor: "#93c5fd" };
|
|
860
808
|
let device = config.device || "mobile";
|
|
861
809
|
let scale = config.scale ?? 1;
|
|
862
810
|
const lang = config.lang || "de";
|
|
863
|
-
const buildSrc =
|
|
811
|
+
const buildSrc = (c, d) => {
|
|
864
812
|
const p = new URLSearchParams({
|
|
865
813
|
mode: "preview",
|
|
866
814
|
isPreview: "true",
|
|
@@ -871,11 +819,11 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
871
819
|
lang
|
|
872
820
|
});
|
|
873
821
|
return `${this.widgetUrl}/?${p.toString()}`;
|
|
874
|
-
}
|
|
875
|
-
const applyScale =
|
|
822
|
+
};
|
|
823
|
+
const applyScale = () => {
|
|
876
824
|
iframe.style.transform = scale !== 1 ? `scale(${scale})` : "";
|
|
877
825
|
iframe.style.transformOrigin = scale !== 1 ? "top left" : "";
|
|
878
|
-
}
|
|
826
|
+
};
|
|
879
827
|
const iframe = document.createElement("iframe");
|
|
880
828
|
iframe.style.cssText = "border:none;width:100%;height:100%;display:block";
|
|
881
829
|
iframe.src = buildSrc(colors, device);
|
|
@@ -887,10 +835,7 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
887
835
|
return {
|
|
888
836
|
iframe,
|
|
889
837
|
setColors(newColors) {
|
|
890
|
-
colors = {
|
|
891
|
-
...colors,
|
|
892
|
-
...newColors
|
|
893
|
-
};
|
|
838
|
+
colors = { ...colors, ...newColors };
|
|
894
839
|
if (newColors.primaryColor && !newColors.secondaryColor) {
|
|
895
840
|
colors.secondaryColor = generateSecondaryColor(newColors.primaryColor);
|
|
896
841
|
}
|
|
@@ -900,42 +845,34 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
900
845
|
device = d;
|
|
901
846
|
iframe.src = buildSrc(colors, device);
|
|
902
847
|
},
|
|
903
|
-
getColors:
|
|
904
|
-
|
|
905
|
-
}), "getColors"),
|
|
906
|
-
destroy: /* @__PURE__ */ __name(() => iframe.remove(), "destroy")
|
|
848
|
+
getColors: () => ({ ...colors }),
|
|
849
|
+
destroy: () => iframe.remove()
|
|
907
850
|
};
|
|
908
851
|
}
|
|
909
852
|
// ── Private flows ────────────────────────────────────
|
|
910
853
|
/**
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
854
|
+
* Flow 1: serverUrl — POST to client's backend, get sessionId + embedToken.
|
|
855
|
+
*
|
|
856
|
+
* When `publishableKey` is provided, design tokens are fetched in parallel
|
|
857
|
+
* with the session creation request. This shows the branded loader ~200-500ms
|
|
858
|
+
* faster because we don't have to wait for the session to be created first.
|
|
859
|
+
*/
|
|
917
860
|
async initWithServerUrl(config) {
|
|
918
861
|
const pk = config.publishableKey;
|
|
919
|
-
const designTokensPromise = pk ? fetchDesignTokens(this.apiBase, {
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
]);
|
|
927
|
-
const primaryColor = earlyTokens?.colors?.primary?.cannabis || "#15BA68";
|
|
928
|
-
const loader = new Loader();
|
|
929
|
-
loader.show(primaryColor, config.lang);
|
|
862
|
+
const designTokensPromise = pk ? fetchDesignTokens(this.apiBase, { pk }) : Promise.resolve(null);
|
|
863
|
+
const sessionPromise = fetchSessionFromServer(
|
|
864
|
+
config.serverUrl,
|
|
865
|
+
config.clientMetadata,
|
|
866
|
+
config.requestHeaders
|
|
867
|
+
);
|
|
868
|
+
const { loader, primaryColor } = await showLoaderWithEarlyColor(designTokensPromise, config.lang);
|
|
930
869
|
try {
|
|
931
870
|
const [{ sessionId, embedToken }, designTokens] = await Promise.all([
|
|
932
871
|
sessionPromise,
|
|
933
872
|
designTokensPromise
|
|
934
873
|
]);
|
|
935
|
-
const finalTokens = designTokens ?? await fetchDesignTokens(this.apiBase, {
|
|
936
|
-
|
|
937
|
-
});
|
|
938
|
-
const finalColor = finalTokens?.colors?.primary?.cannabis || "#15BA68";
|
|
874
|
+
const finalTokens = designTokens ?? await fetchDesignTokens(this.apiBase, { sessionId });
|
|
875
|
+
const finalColor = primaryFrom(finalTokens);
|
|
939
876
|
if (finalColor !== primaryColor) loader.updateColor(finalColor);
|
|
940
877
|
const sessionData = await fetchPublicSession(this.apiBase, sessionId, embedToken);
|
|
941
878
|
const session = {
|
|
@@ -959,17 +896,24 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
959
896
|
}
|
|
960
897
|
}
|
|
961
898
|
/**
|
|
962
|
-
|
|
963
|
-
|
|
899
|
+
* Flow 2: sessionId + embedToken — fetch session data, open widget.
|
|
900
|
+
*/
|
|
964
901
|
async initWithEmbedToken(config) {
|
|
965
|
-
const
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
902
|
+
const pk = config.publishableKey;
|
|
903
|
+
const designTokensPromise = pk ? fetchDesignTokens(this.apiBase, { pk }) : fetchDesignTokens(this.apiBase, { sessionId: config.sessionId });
|
|
904
|
+
const sessionPromise = fetchPublicSession(
|
|
905
|
+
this.apiBase,
|
|
906
|
+
config.sessionId,
|
|
907
|
+
config.embedToken
|
|
908
|
+
);
|
|
909
|
+
const { loader, primaryColor } = await showLoaderWithEarlyColor(designTokensPromise, config.lang);
|
|
971
910
|
try {
|
|
972
|
-
const sessionData = await
|
|
911
|
+
const [sessionData, designTokens] = await Promise.all([
|
|
912
|
+
sessionPromise,
|
|
913
|
+
designTokensPromise
|
|
914
|
+
]);
|
|
915
|
+
const finalColor = primaryFrom(designTokens);
|
|
916
|
+
if (finalColor !== primaryColor) loader.updateColor(finalColor);
|
|
973
917
|
const session = {
|
|
974
918
|
id: sessionData.id,
|
|
975
919
|
allowManualUpload: sessionData.allowManualUpload ?? config.allowManualUpload ?? true,
|
|
@@ -991,17 +935,23 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
991
935
|
}
|
|
992
936
|
}
|
|
993
937
|
/**
|
|
994
|
-
|
|
995
|
-
|
|
938
|
+
* Flow 3: sessionId only — exchange for embedToken, then init.
|
|
939
|
+
*
|
|
940
|
+
* @deprecated Prefer flow 2 (`sessionId` + `embedToken`). Return the
|
|
941
|
+
* `embedToken` from your backend together with the `sessionId` to skip this
|
|
942
|
+
* extra token-exchange round-trip.
|
|
943
|
+
*/
|
|
996
944
|
async initWithSession(config) {
|
|
997
|
-
const
|
|
945
|
+
const designTokensPromise = fetchDesignTokens(this.apiBase, {
|
|
998
946
|
sessionId: config.sessionId
|
|
999
947
|
});
|
|
1000
|
-
const
|
|
1001
|
-
const loader =
|
|
1002
|
-
loader.show(primaryColor, config.lang);
|
|
948
|
+
const exchangePromise = exchangeSessionForToken(this.apiBase, config.sessionId);
|
|
949
|
+
const { loader } = await showLoaderWithEarlyColor(designTokensPromise, config.lang);
|
|
1003
950
|
try {
|
|
1004
|
-
const { embedToken, session } = await
|
|
951
|
+
const [{ embedToken, session }, designTokens] = await Promise.all([
|
|
952
|
+
exchangePromise,
|
|
953
|
+
designTokensPromise
|
|
954
|
+
]);
|
|
1005
955
|
return this.buildWidget(embedToken, session, config, loader, designTokens);
|
|
1006
956
|
} catch (err) {
|
|
1007
957
|
const msg = err.message || "Failed to initialize verification";
|
|
@@ -1011,18 +961,15 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
1011
961
|
}
|
|
1012
962
|
}
|
|
1013
963
|
/**
|
|
1014
|
-
|
|
1015
|
-
|
|
964
|
+
* Flow 4: publishableKey — fetch widget token, open widget.
|
|
965
|
+
*/
|
|
1016
966
|
async initWithPublishableKey(config) {
|
|
1017
967
|
const pk = config.publishableKey;
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
});
|
|
1021
|
-
const primaryColor = designTokens?.colors?.primary?.cannabis || "#15BA68";
|
|
1022
|
-
const loader = new Loader();
|
|
1023
|
-
loader.show(primaryColor, config.lang);
|
|
968
|
+
const designTokensPromise = fetchDesignTokens(this.apiBase, { pk });
|
|
969
|
+
const widgetTokenPromise = fetchWidgetToken(pk, this.apiBase);
|
|
970
|
+
const { loader, primaryColor } = await showLoaderWithEarlyColor(designTokensPromise, config.lang);
|
|
1024
971
|
try {
|
|
1025
|
-
const data = await
|
|
972
|
+
const data = await widgetTokenPromise;
|
|
1026
973
|
const params = {
|
|
1027
974
|
mode: "embedded",
|
|
1028
975
|
publishableKey: pk,
|
|
@@ -1077,7 +1024,7 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
1077
1024
|
if (config.lang) params.lang = config.lang;
|
|
1078
1025
|
if (config.overlayColor) params.overlayColor = config.overlayColor;
|
|
1079
1026
|
return this.openWidget(params, {
|
|
1080
|
-
primaryColor: designTokens
|
|
1027
|
+
primaryColor: primaryFrom(designTokens),
|
|
1081
1028
|
lang: config.lang,
|
|
1082
1029
|
loader,
|
|
1083
1030
|
onSuccess: config.onSuccess,
|
|
@@ -1088,10 +1035,12 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
1088
1035
|
});
|
|
1089
1036
|
}
|
|
1090
1037
|
/**
|
|
1091
|
-
|
|
1092
|
-
|
|
1038
|
+
* Core: create iframe, attach listeners, return WidgetInstance.
|
|
1039
|
+
*/
|
|
1093
1040
|
openWidget(params, opts) {
|
|
1094
|
-
const filtered = Object.fromEntries(
|
|
1041
|
+
const filtered = Object.fromEntries(
|
|
1042
|
+
Object.entries(params).filter(([, v]) => v != null)
|
|
1043
|
+
);
|
|
1095
1044
|
const search = new URLSearchParams(filtered);
|
|
1096
1045
|
const src = `${this.widgetUrl}/?${search.toString()}`;
|
|
1097
1046
|
const iframe = createIframe(src);
|
|
@@ -1105,7 +1054,7 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
1105
1054
|
mountTarget.appendChild(iframe);
|
|
1106
1055
|
const cleanupViewport = setupViewportSizing(loader.element, iframe);
|
|
1107
1056
|
let cleaned = false;
|
|
1108
|
-
const cleanupAll =
|
|
1057
|
+
const cleanupAll = () => {
|
|
1109
1058
|
if (cleaned) return;
|
|
1110
1059
|
cleaned = true;
|
|
1111
1060
|
try {
|
|
@@ -1115,26 +1064,28 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
1115
1064
|
if (iframe.parentNode) iframe.remove();
|
|
1116
1065
|
} catch {
|
|
1117
1066
|
}
|
|
1118
|
-
}
|
|
1119
|
-
const afterCleanup =
|
|
1067
|
+
};
|
|
1068
|
+
const afterCleanup = (delayMs) => setTimeout(cleanupAll, delayMs);
|
|
1120
1069
|
const handler = new MessageHandler(src, iframe, {
|
|
1121
|
-
onSuccess:
|
|
1070
|
+
onSuccess: (r) => {
|
|
1122
1071
|
opts.onSuccess?.(r);
|
|
1123
|
-
afterCleanup(1e3)
|
|
1124
|
-
}
|
|
1125
|
-
onError:
|
|
1072
|
+
afterCleanup(1e3);
|
|
1073
|
+
},
|
|
1074
|
+
onError: (e) => {
|
|
1126
1075
|
opts.onError?.(e);
|
|
1127
|
-
afterCleanup(500)
|
|
1128
|
-
}
|
|
1129
|
-
onCancel:
|
|
1076
|
+
afterCleanup(500);
|
|
1077
|
+
},
|
|
1078
|
+
onCancel: () => {
|
|
1130
1079
|
opts.onCancel?.();
|
|
1131
|
-
afterCleanup(500)
|
|
1132
|
-
}
|
|
1080
|
+
afterCleanup(500);
|
|
1081
|
+
},
|
|
1133
1082
|
onReady: opts.onReady
|
|
1134
1083
|
});
|
|
1135
1084
|
handler.listen();
|
|
1136
1085
|
handler.onReadyOnce(() => {
|
|
1137
|
-
|
|
1086
|
+
if (loader.element) {
|
|
1087
|
+
transitionLoaderToIframe(loader.element, iframe, () => loader.destroy());
|
|
1088
|
+
}
|
|
1138
1089
|
});
|
|
1139
1090
|
return {
|
|
1140
1091
|
iframe,
|
|
@@ -1142,31 +1093,34 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
1142
1093
|
};
|
|
1143
1094
|
}
|
|
1144
1095
|
};
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1096
|
+
FlonkKYC.version = SDK_VERSION;
|
|
1097
|
+
function FlonkKYCWidget({
|
|
1098
|
+
widgetUrl,
|
|
1099
|
+
apiBase,
|
|
1100
|
+
autoOpen = true,
|
|
1101
|
+
publishableKey,
|
|
1102
|
+
serverUrl,
|
|
1103
|
+
sessionId,
|
|
1104
|
+
embedToken,
|
|
1105
|
+
clientMetadata,
|
|
1106
|
+
lang,
|
|
1107
|
+
overlayColor,
|
|
1108
|
+
allowManualUpload,
|
|
1109
|
+
requestHeaders,
|
|
1110
|
+
onSuccess,
|
|
1111
|
+
onError,
|
|
1112
|
+
onCancel,
|
|
1113
|
+
onReady
|
|
1114
|
+
}) {
|
|
1149
1115
|
const mountRef = useRef(null);
|
|
1150
1116
|
const widgetRef = useRef(null);
|
|
1151
|
-
const callbacksRef = useRef({
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
onSuccess,
|
|
1159
|
-
onError,
|
|
1160
|
-
onCancel,
|
|
1161
|
-
onReady
|
|
1162
|
-
};
|
|
1163
|
-
const sdk = useMemo(() => new FlonkKYC({
|
|
1164
|
-
widgetUrl,
|
|
1165
|
-
apiBase
|
|
1166
|
-
}), [
|
|
1167
|
-
widgetUrl,
|
|
1168
|
-
apiBase
|
|
1169
|
-
]);
|
|
1117
|
+
const callbacksRef = useRef({ onSuccess, onError, onCancel, onReady });
|
|
1118
|
+
callbacksRef.current = { onSuccess, onError, onCancel, onReady };
|
|
1119
|
+
const sdk = useMemo(() => new FlonkKYC({ widgetUrl, apiBase }), [widgetUrl, apiBase]);
|
|
1120
|
+
useEffect(() => {
|
|
1121
|
+
if (!publishableKey && !sessionId) return;
|
|
1122
|
+
void FlonkKYC.preloadBranding({ publishableKey, sessionId, apiBase });
|
|
1123
|
+
}, [publishableKey, sessionId, apiBase]);
|
|
1170
1124
|
const generationRef = useRef(0);
|
|
1171
1125
|
useEffect(() => {
|
|
1172
1126
|
if (!autoOpen) return;
|
|
@@ -1182,10 +1136,10 @@ function FlonkKYCWidget({ widgetUrl, apiBase, autoOpen = true, publishableKey, s
|
|
|
1182
1136
|
allowManualUpload,
|
|
1183
1137
|
requestHeaders,
|
|
1184
1138
|
mount: mountRef.current || void 0,
|
|
1185
|
-
onSuccess:
|
|
1186
|
-
onError:
|
|
1187
|
-
onCancel:
|
|
1188
|
-
onReady:
|
|
1139
|
+
onSuccess: (r) => callbacksRef.current.onSuccess?.(r),
|
|
1140
|
+
onError: (e) => callbacksRef.current.onError?.(e),
|
|
1141
|
+
onCancel: () => callbacksRef.current.onCancel?.(),
|
|
1142
|
+
onReady: () => callbacksRef.current.onReady?.()
|
|
1189
1143
|
};
|
|
1190
1144
|
const timer = setTimeout(() => {
|
|
1191
1145
|
if (generationRef.current !== thisGeneration) return;
|
|
@@ -1206,19 +1160,20 @@ function FlonkKYCWidget({ widgetUrl, apiBase, autoOpen = true, publishableKey, s
|
|
|
1206
1160
|
widgetRef.current?.destroy();
|
|
1207
1161
|
widgetRef.current = null;
|
|
1208
1162
|
};
|
|
1209
|
-
}, [
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1163
|
+
}, [sdk, publishableKey, serverUrl, sessionId, embedToken, lang, overlayColor, allowManualUpload, autoOpen]);
|
|
1164
|
+
return /* @__PURE__ */ jsx("div", { ref: mountRef });
|
|
1165
|
+
}
|
|
1166
|
+
function FlonkKYCBrandingPreloader({
|
|
1167
|
+
publishableKey,
|
|
1168
|
+
sessionId,
|
|
1169
|
+
apiBase
|
|
1170
|
+
}) {
|
|
1171
|
+
useEffect(() => {
|
|
1172
|
+
void FlonkKYC.preloadBranding({ publishableKey, sessionId, apiBase });
|
|
1173
|
+
}, [publishableKey, sessionId, apiBase]);
|
|
1174
|
+
return null;
|
|
1219
1175
|
}
|
|
1220
|
-
__name(FlonkKYCWidget, "FlonkKYCWidget");
|
|
1221
1176
|
|
|
1222
|
-
export { FlonkError, FlonkKYC, FlonkKYCWidget, FlonkValidationError };
|
|
1177
|
+
export { FlonkError, FlonkKYC, FlonkKYCBrandingPreloader, FlonkKYCWidget, FlonkValidationError };
|
|
1223
1178
|
//# sourceMappingURL=index.js.map
|
|
1224
1179
|
//# sourceMappingURL=index.js.map
|