@flonkid/kyc 1.6.1 → 1.7.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 +257 -358
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -9
- package/dist/index.d.ts +21 -9
- package/dist/index.js +257 -358
- 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.7.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,44 @@ async function fetchWidgetToken(pk, apiBase) {
|
|
|
106
104
|
}
|
|
107
105
|
return res.json();
|
|
108
106
|
}
|
|
109
|
-
__name(fetchWidgetToken, "fetchWidgetToken");
|
|
110
107
|
async function fetchDesignTokens(apiBase, opts) {
|
|
111
108
|
const params = [];
|
|
112
109
|
if (opts.sessionId) params.push(`sessionId=${encodeURIComponent(opts.sessionId)}`);
|
|
113
110
|
else if (opts.clientId) params.push(`clientId=${encodeURIComponent(opts.clientId)}`);
|
|
114
111
|
const url = `${apiBase}/public/design-tokens${params.length ? "?" + params.join("&") : ""}`;
|
|
115
112
|
try {
|
|
116
|
-
const res = await
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
});
|
|
113
|
+
const res = await fetchWithTimeout(
|
|
114
|
+
url,
|
|
115
|
+
{ headers: opts.pk ? { "x-kyc-pk": opts.pk } : {}, credentials: "omit" },
|
|
116
|
+
8e3
|
|
117
|
+
);
|
|
122
118
|
return res.ok ? res.json() : null;
|
|
123
119
|
} catch {
|
|
124
120
|
return null;
|
|
125
121
|
}
|
|
126
122
|
}
|
|
127
|
-
__name(fetchDesignTokens, "fetchDesignTokens");
|
|
128
123
|
function validateServerUrl(url) {
|
|
129
124
|
if (url.startsWith("/")) return;
|
|
130
125
|
try {
|
|
131
126
|
const parsed = new URL(url);
|
|
132
127
|
const isLocalhost = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
133
128
|
if (parsed.protocol !== "https:" && !isLocalhost) {
|
|
134
|
-
throw new Error(
|
|
129
|
+
throw new Error(
|
|
130
|
+
`serverUrl must use HTTPS in production. Got: ${parsed.protocol}//. Use HTTPS ('https://api.myapp.com/...') or a relative path ('/api/...')`
|
|
131
|
+
);
|
|
135
132
|
}
|
|
136
133
|
} catch (e) {
|
|
137
134
|
if (e.message.includes("serverUrl must use HTTPS")) throw e;
|
|
138
135
|
throw new Error(`Invalid serverUrl: ${url}`);
|
|
139
136
|
}
|
|
140
137
|
}
|
|
141
|
-
__name(validateServerUrl, "validateServerUrl");
|
|
142
138
|
async function fetchSessionFromServer(serverUrl, clientMetadata, requestHeaders) {
|
|
143
139
|
validateServerUrl(serverUrl);
|
|
144
|
-
const res = await
|
|
140
|
+
const res = await fetchWithTimeout(serverUrl, {
|
|
145
141
|
method: "POST",
|
|
146
|
-
headers: {
|
|
147
|
-
"Content-Type": "application/json",
|
|
148
|
-
...requestHeaders
|
|
149
|
-
},
|
|
142
|
+
headers: { "Content-Type": "application/json", ...requestHeaders },
|
|
150
143
|
credentials: "include",
|
|
151
|
-
body: JSON.stringify({
|
|
152
|
-
clientMetadata
|
|
153
|
-
})
|
|
144
|
+
body: JSON.stringify({ clientMetadata })
|
|
154
145
|
});
|
|
155
146
|
if (!res.ok) {
|
|
156
147
|
let message = `Session request failed (${res.status})`;
|
|
@@ -164,9 +155,8 @@ async function fetchSessionFromServer(serverUrl, clientMetadata, requestHeaders)
|
|
|
164
155
|
}
|
|
165
156
|
return res.json();
|
|
166
157
|
}
|
|
167
|
-
__name(fetchSessionFromServer, "fetchSessionFromServer");
|
|
168
158
|
async function fetchPublicSession(apiBase, sessionId, embedToken) {
|
|
169
|
-
const res = await
|
|
159
|
+
const res = await fetchWithTimeout(`${apiBase}/public/session/${sessionId}`, {
|
|
170
160
|
headers: {
|
|
171
161
|
"Content-Type": "application/json",
|
|
172
162
|
"Authorization": `Bearer ${embedToken}`
|
|
@@ -183,13 +173,10 @@ async function fetchPublicSession(apiBase, sessionId, embedToken) {
|
|
|
183
173
|
}
|
|
184
174
|
return res.json();
|
|
185
175
|
}
|
|
186
|
-
__name(fetchPublicSession, "fetchPublicSession");
|
|
187
176
|
async function exchangeSessionForToken(apiBase, sessionId) {
|
|
188
|
-
const res = await
|
|
177
|
+
const res = await fetchWithTimeout(`${apiBase}/public/session/${sessionId}/token`, {
|
|
189
178
|
method: "POST",
|
|
190
|
-
headers: {
|
|
191
|
-
"Content-Type": "application/json"
|
|
192
|
-
}
|
|
179
|
+
headers: { "Content-Type": "application/json" }
|
|
193
180
|
});
|
|
194
181
|
if (!res.ok) {
|
|
195
182
|
let message = `Token exchange failed (${res.status})`;
|
|
@@ -202,33 +189,36 @@ async function exchangeSessionForToken(apiBase, sessionId) {
|
|
|
202
189
|
}
|
|
203
190
|
return res.json();
|
|
204
191
|
}
|
|
205
|
-
__name(exchangeSessionForToken, "exchangeSessionForToken");
|
|
206
192
|
|
|
207
193
|
// src/browser/iframe-manager.ts
|
|
208
194
|
function createIframe(src) {
|
|
209
195
|
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
|
-
|
|
196
|
+
const iframe = createEl(
|
|
197
|
+
"iframe",
|
|
198
|
+
{
|
|
199
|
+
border: "0",
|
|
200
|
+
width: window.innerWidth + "px",
|
|
201
|
+
height: window.innerHeight + "px",
|
|
202
|
+
position: "fixed",
|
|
203
|
+
top: "0",
|
|
204
|
+
left: "0",
|
|
205
|
+
zIndex: "9999",
|
|
206
|
+
background: "transparent",
|
|
207
|
+
backgroundColor: "transparent",
|
|
208
|
+
opacity: "0",
|
|
209
|
+
visibility: "hidden",
|
|
210
|
+
borderRadius: d ? "0" : "",
|
|
211
|
+
boxShadow: d ? "none" : "",
|
|
212
|
+
colorScheme: "normal"
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
src,
|
|
216
|
+
allow: "camera;microphone;clipboard-read;clipboard-write",
|
|
217
|
+
sandbox: "allow-scripts allow-forms allow-same-origin allow-popups",
|
|
218
|
+
"aria-label": "KYC Verification",
|
|
219
|
+
allowtransparency: "true"
|
|
220
|
+
}
|
|
221
|
+
);
|
|
232
222
|
try {
|
|
233
223
|
iframe.style.setProperty("background", "transparent", "important");
|
|
234
224
|
iframe.style.setProperty("background-color", "transparent", "important");
|
|
@@ -237,24 +227,21 @@ function createIframe(src) {
|
|
|
237
227
|
}
|
|
238
228
|
return iframe;
|
|
239
229
|
}
|
|
240
|
-
__name(createIframe, "createIframe");
|
|
241
230
|
function adjustZIndex(loader, iframe) {
|
|
242
231
|
if (!isDesktop()) return;
|
|
243
232
|
const all = Array.from(document.querySelectorAll("*"));
|
|
244
|
-
const maxZ = Math.max(
|
|
233
|
+
const maxZ = Math.max(
|
|
234
|
+
...all.map((el) => parseInt(getComputedStyle(el).zIndex) || 0).filter((z) => z < 999999)
|
|
235
|
+
);
|
|
245
236
|
if (maxZ > 9998) {
|
|
246
237
|
loader.style.zIndex = String(maxZ + 1);
|
|
247
238
|
iframe.style.zIndex = String(maxZ + 2);
|
|
248
239
|
}
|
|
249
240
|
}
|
|
250
|
-
__name(adjustZIndex, "adjustZIndex");
|
|
251
241
|
function transitionLoaderToIframe(loader, iframe, onDone) {
|
|
252
242
|
const d = isDesktop();
|
|
253
243
|
const dur = d ? 300 : 500;
|
|
254
|
-
setStyles(iframe, {
|
|
255
|
-
opacity: "0",
|
|
256
|
-
visibility: "hidden"
|
|
257
|
-
});
|
|
244
|
+
setStyles(iframe, { opacity: "0", visibility: "hidden" });
|
|
258
245
|
const card = loader.querySelector("div");
|
|
259
246
|
if (card) {
|
|
260
247
|
setStyles(card, {
|
|
@@ -272,28 +259,12 @@ function transitionLoaderToIframe(loader, iframe, onDone) {
|
|
|
272
259
|
});
|
|
273
260
|
}, dur);
|
|
274
261
|
}
|
|
275
|
-
__name(transitionLoaderToIframe, "transitionLoaderToIframe");
|
|
276
262
|
|
|
277
263
|
// src/browser/loader.ts
|
|
278
264
|
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
|
-
}
|
|
265
|
+
en: { title: "Initializing...", subtitle: "Loading KYC widget", errorTitle: "Something went wrong", close: "Close" },
|
|
266
|
+
de: { title: "Initialisierung...", subtitle: "KYC-Widget wird geladen", errorTitle: "Ein Fehler ist aufgetreten", close: "Schlie\xDFen" },
|
|
267
|
+
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
268
|
};
|
|
298
269
|
var KEYFRAMES = `
|
|
299
270
|
@keyframes kycspin{0%{transform:rotate(0)}100%{transform:rotate(360deg)}}
|
|
@@ -301,11 +272,11 @@ var KEYFRAMES = `
|
|
|
301
272
|
@keyframes kycprogress{0%{transform:translateX(-100%)}50%{transform:translateX(0%)}100%{transform:translateX(250%)}}
|
|
302
273
|
`.trim();
|
|
303
274
|
var styleInjected = false;
|
|
304
|
-
var
|
|
275
|
+
var Loader = class {
|
|
305
276
|
constructor() {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
277
|
+
this.overlay = null;
|
|
278
|
+
this.cleanup = null;
|
|
279
|
+
this.origBodyStyles = null;
|
|
309
280
|
}
|
|
310
281
|
show(primaryColor, lang) {
|
|
311
282
|
const color = primaryColor || "#15BA68";
|
|
@@ -384,64 +355,23 @@ var _Loader = class _Loader {
|
|
|
384
355
|
"stroke-dasharray": "62.8",
|
|
385
356
|
"stroke-dashoffset": "15.7"
|
|
386
357
|
})) fg.setAttribute(k, v);
|
|
387
|
-
setStyles(fg, {
|
|
388
|
-
transformOrigin: "center",
|
|
389
|
-
animation: "kycdash 1.5s ease-in-out infinite"
|
|
390
|
-
});
|
|
358
|
+
setStyles(fg, { transformOrigin: "center", animation: "kycdash 1.5s ease-in-out infinite" });
|
|
391
359
|
svg.append(bg, fg);
|
|
392
360
|
wrap.appendChild(svg);
|
|
393
361
|
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
|
-
});
|
|
362
|
+
const textBox = createEl("div", { textAlign: "center" });
|
|
363
|
+
const title = createEl("h3", { fontFamily: font, fontWeight: "600", fontSize: "18px", lineHeight: "1.3", color: "#1F2937", margin: "0 0 4px 0" });
|
|
405
364
|
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
|
-
});
|
|
365
|
+
const subtitle = createEl("p", { fontFamily: font, fontWeight: "400", fontSize: "13px", lineHeight: "1.4", color: "rgba(31,41,55,0.7)", margin: "0" });
|
|
414
366
|
subtitle.textContent = strings.subtitle;
|
|
415
367
|
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
|
-
});
|
|
368
|
+
const track = createEl("div", { width: "100%", maxWidth: "240px", height: "3px", backgroundColor: color + "1A", borderRadius: "2px", overflow: "hidden" });
|
|
369
|
+
const bar = createEl("div", { width: "40%", height: "100%", backgroundColor: color, borderRadius: "2px", transform: "translateX(-100%)", animation: "kycprogress 2000ms ease-in-out infinite" });
|
|
432
370
|
track.appendChild(bar);
|
|
433
371
|
card.append(wrap, textBox, track);
|
|
434
372
|
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
|
-
});
|
|
373
|
+
this.origBodyStyles = { overflow: document.body.style.overflow, position: document.body.style.position };
|
|
374
|
+
setStyles(document.body, { overflow: "hidden", position: "fixed", width: "100%", height: "100%" });
|
|
445
375
|
document.body.appendChild(overlay);
|
|
446
376
|
let prevW = window.innerWidth;
|
|
447
377
|
let prevH = window.innerHeight;
|
|
@@ -449,10 +379,7 @@ var _Loader = class _Loader {
|
|
|
449
379
|
const w = window.innerWidth;
|
|
450
380
|
const h = window.innerHeight;
|
|
451
381
|
if (Math.abs(w - prevW) > 1 || Math.abs(h - prevH) > 1) {
|
|
452
|
-
setStyles(overlay, {
|
|
453
|
-
width: w + "px",
|
|
454
|
-
height: h + "px"
|
|
455
|
-
});
|
|
382
|
+
setStyles(overlay, { width: w + "px", height: h + "px" });
|
|
456
383
|
prevW = w;
|
|
457
384
|
prevH = h;
|
|
458
385
|
}
|
|
@@ -462,11 +389,7 @@ var _Loader = class _Loader {
|
|
|
462
389
|
this.cleanup = () => {
|
|
463
390
|
window.removeEventListener("resize", onResize);
|
|
464
391
|
if (this.origBodyStyles) {
|
|
465
|
-
setStyles(document.body, {
|
|
466
|
-
...this.origBodyStyles,
|
|
467
|
-
width: "",
|
|
468
|
-
height: ""
|
|
469
|
-
});
|
|
392
|
+
setStyles(document.body, { ...this.origBodyStyles, width: "", height: "" });
|
|
470
393
|
}
|
|
471
394
|
};
|
|
472
395
|
return overlay;
|
|
@@ -586,25 +509,20 @@ var _Loader = class _Loader {
|
|
|
586
509
|
this.cleanup = null;
|
|
587
510
|
}
|
|
588
511
|
};
|
|
589
|
-
__name(_Loader, "Loader");
|
|
590
|
-
var Loader = _Loader;
|
|
591
512
|
|
|
592
513
|
// src/browser/message-handler.ts
|
|
593
|
-
var
|
|
514
|
+
var MessageHandler = class {
|
|
594
515
|
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
516
|
this.iframeSrc = iframeSrc;
|
|
602
517
|
this.iframe = iframe;
|
|
603
518
|
this.callbacks = callbacks;
|
|
519
|
+
this.listener = null;
|
|
520
|
+
this.readyListener = null;
|
|
521
|
+
this.completionHandled = false;
|
|
604
522
|
}
|
|
605
523
|
/**
|
|
606
|
-
|
|
607
|
-
|
|
524
|
+
* Start listening for postMessage events from the widget iframe.
|
|
525
|
+
*/
|
|
608
526
|
listen() {
|
|
609
527
|
const origin = getOrigin(this.iframeSrc);
|
|
610
528
|
this.listener = (e) => {
|
|
@@ -612,34 +530,33 @@ var _MessageHandler = class _MessageHandler {
|
|
|
612
530
|
if (e.source !== this.iframe.contentWindow) return;
|
|
613
531
|
const data = e.data || {};
|
|
614
532
|
const type = data.type;
|
|
615
|
-
if (type === WIDGET_EVENTS.COMPLETE
|
|
533
|
+
if (type === WIDGET_EVENTS.COMPLETE) {
|
|
616
534
|
if (this.completionHandled) return;
|
|
617
535
|
this.completionHandled = true;
|
|
618
|
-
this.callbacks.onSuccess(data.result);
|
|
619
|
-
|
|
620
|
-
} else if (type === WIDGET_EVENTS.CANCEL && this.callbacks.onCancel) {
|
|
536
|
+
this.callbacks.onSuccess?.(data.result);
|
|
537
|
+
} else if (type === WIDGET_EVENTS.CANCEL) {
|
|
621
538
|
if (this.completionHandled) return;
|
|
622
539
|
this.completionHandled = true;
|
|
623
|
-
this.callbacks.onCancel();
|
|
624
|
-
|
|
625
|
-
} else if (type === WIDGET_EVENTS.ERROR && this.callbacks.onError) {
|
|
540
|
+
this.callbacks.onCancel?.();
|
|
541
|
+
} else if (type === WIDGET_EVENTS.ERROR) {
|
|
626
542
|
if (this.completionHandled) return;
|
|
627
543
|
this.completionHandled = true;
|
|
628
|
-
this.callbacks.onError(data.error || "Unknown error");
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
this.callbacks.onReady();
|
|
544
|
+
this.callbacks.onError?.(data.error || "Unknown error");
|
|
545
|
+
} else if (type === WIDGET_EVENTS.READY) {
|
|
546
|
+
this.callbacks.onReady?.();
|
|
632
547
|
}
|
|
633
548
|
};
|
|
634
549
|
window.addEventListener("message", this.listener);
|
|
635
550
|
}
|
|
636
551
|
/**
|
|
637
|
-
|
|
638
|
-
|
|
552
|
+
* Listen for the first READY event, then call the callback once.
|
|
553
|
+
*/
|
|
639
554
|
onReadyOnce(callback) {
|
|
640
555
|
const origin = getOrigin(this.iframeSrc);
|
|
641
556
|
this.readyListener = (e) => {
|
|
642
|
-
if (e.origin !== origin || e.data?.type !== WIDGET_EVENTS.READY)
|
|
557
|
+
if (e.origin !== origin || e.source !== this.iframe.contentWindow || e.data?.type !== WIDGET_EVENTS.READY) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
643
560
|
window.removeEventListener("message", this.readyListener);
|
|
644
561
|
this.readyListener = null;
|
|
645
562
|
callback();
|
|
@@ -657,8 +574,6 @@ var _MessageHandler = class _MessageHandler {
|
|
|
657
574
|
}
|
|
658
575
|
}
|
|
659
576
|
};
|
|
660
|
-
__name(_MessageHandler, "MessageHandler");
|
|
661
|
-
var MessageHandler = _MessageHandler;
|
|
662
577
|
|
|
663
578
|
// src/browser/viewport.ts
|
|
664
579
|
function getVV() {
|
|
@@ -670,14 +585,8 @@ function getVV() {
|
|
|
670
585
|
offsetLeft: window.visualViewport.offsetLeft || 0
|
|
671
586
|
};
|
|
672
587
|
}
|
|
673
|
-
return {
|
|
674
|
-
width: window.innerWidth,
|
|
675
|
-
height: window.innerHeight,
|
|
676
|
-
offsetTop: 0,
|
|
677
|
-
offsetLeft: 0
|
|
678
|
-
};
|
|
588
|
+
return { width: window.innerWidth, height: window.innerHeight, offsetTop: 0, offsetLeft: 0 };
|
|
679
589
|
}
|
|
680
|
-
__name(getVV, "getVV");
|
|
681
590
|
function ensureViewportMeta() {
|
|
682
591
|
try {
|
|
683
592
|
const meta = document.querySelector('meta[name="viewport"]');
|
|
@@ -695,42 +604,31 @@ function ensureViewportMeta() {
|
|
|
695
604
|
} catch {
|
|
696
605
|
}
|
|
697
606
|
}
|
|
698
|
-
__name(ensureViewportMeta, "ensureViewportMeta");
|
|
699
607
|
function setupViewportSizing(overlay, iframe) {
|
|
700
608
|
ensureViewportMeta();
|
|
701
609
|
let baselineHeight = 0;
|
|
702
610
|
let desktop = isDesktop();
|
|
703
611
|
let rafId = null;
|
|
704
|
-
const initBaseline =
|
|
612
|
+
const initBaseline = () => {
|
|
705
613
|
const vv = getVV();
|
|
706
614
|
baselineHeight = window.innerHeight || vv.height || document.documentElement.clientHeight || 0;
|
|
707
615
|
desktop = isDesktop();
|
|
708
616
|
if (rafId) cancelAnimationFrame(rafId);
|
|
709
617
|
rafId = requestAnimationFrame(applySize);
|
|
710
|
-
}
|
|
711
|
-
const applySize =
|
|
618
|
+
};
|
|
619
|
+
const applySize = () => {
|
|
712
620
|
try {
|
|
713
621
|
const vv = getVV();
|
|
714
622
|
const inner = window.innerHeight || vv.height;
|
|
715
623
|
const kbThreshold = desktop ? 200 : 150;
|
|
716
624
|
const isKeyboard = inner - vv.height > kbThreshold;
|
|
717
625
|
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
|
-
};
|
|
626
|
+
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
627
|
if (overlay) setStyles(overlay, dims);
|
|
730
628
|
if (iframe) setStyles(iframe, dims);
|
|
731
629
|
} catch {
|
|
732
630
|
}
|
|
733
|
-
}
|
|
631
|
+
};
|
|
734
632
|
let prevW = window.innerWidth;
|
|
735
633
|
let prevH = window.innerHeight;
|
|
736
634
|
let prevX = 0;
|
|
@@ -739,7 +637,7 @@ function setupViewportSizing(overlay, iframe) {
|
|
|
739
637
|
if (rafId) cancelAnimationFrame(rafId);
|
|
740
638
|
rafId = requestAnimationFrame(applySize);
|
|
741
639
|
}, desktop ? 50 : 150);
|
|
742
|
-
const handleResize =
|
|
640
|
+
const handleResize = () => {
|
|
743
641
|
const vv = getVV();
|
|
744
642
|
const w = vv.width;
|
|
745
643
|
const h = vv.height;
|
|
@@ -758,12 +656,12 @@ function setupViewportSizing(overlay, iframe) {
|
|
|
758
656
|
} else {
|
|
759
657
|
debouncedApply();
|
|
760
658
|
}
|
|
761
|
-
}
|
|
762
|
-
const handleOrientation =
|
|
659
|
+
};
|
|
660
|
+
const handleOrientation = () => {
|
|
763
661
|
initBaseline();
|
|
764
662
|
if (rafId) cancelAnimationFrame(rafId);
|
|
765
663
|
rafId = requestAnimationFrame(applySize);
|
|
766
|
-
}
|
|
664
|
+
};
|
|
767
665
|
initBaseline();
|
|
768
666
|
applySize();
|
|
769
667
|
window.addEventListener("resize", handleResize);
|
|
@@ -785,26 +683,38 @@ function setupViewportSizing(overlay, iframe) {
|
|
|
785
683
|
}
|
|
786
684
|
};
|
|
787
685
|
}
|
|
788
|
-
__name(setupViewportSizing, "setupViewportSizing");
|
|
789
686
|
|
|
790
687
|
// src/browser/index.ts
|
|
791
|
-
var
|
|
688
|
+
var FALLBACK_PRIMARY = "#15BA68";
|
|
689
|
+
var EARLY_COLOR_BUDGET_MS = 800;
|
|
690
|
+
var primaryFrom = (tokens) => tokens?.colors?.primary?.cannabis || FALLBACK_PRIMARY;
|
|
691
|
+
async function showLoaderWithEarlyColor(tokensPromise, lang) {
|
|
692
|
+
const earlyTokens = await Promise.race([
|
|
693
|
+
tokensPromise,
|
|
694
|
+
new Promise((resolve) => setTimeout(() => resolve(null), EARLY_COLOR_BUDGET_MS))
|
|
695
|
+
]);
|
|
696
|
+
const primaryColor = primaryFrom(earlyTokens);
|
|
697
|
+
const loader = new Loader();
|
|
698
|
+
loader.show(primaryColor, lang);
|
|
699
|
+
return { loader, primaryColor };
|
|
700
|
+
}
|
|
701
|
+
var FlonkKYC = class {
|
|
792
702
|
constructor(options = {}) {
|
|
793
|
-
__publicField(this, "widgetUrl");
|
|
794
|
-
__publicField(this, "apiBase");
|
|
795
703
|
this.widgetUrl = (options.widgetUrl || DEFAULT_WIDGET_URL).replace(/\/$/, "");
|
|
796
704
|
this.apiBase = (options.apiBase || DEFAULT_API_BASE).replace(/\/$/, "");
|
|
797
705
|
}
|
|
798
706
|
// ── Public API ───────────────────────────────────────
|
|
799
707
|
/**
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
708
|
+
* Open the KYC verification widget.
|
|
709
|
+
*
|
|
710
|
+
* Flows (pick one; add `publishableKey` to any for an instant branded loader):
|
|
711
|
+
* 1. `{ serverUrl }` — SDK auto-creates the session via your backend (recommended).
|
|
712
|
+
* 2. `{ sessionId, embedToken }` — you created the session; pass its credentials.
|
|
713
|
+
* 3. `{ sessionId }` — **deprecated**: exchanges the sessionId for an embedToken
|
|
714
|
+
* via an extra round-trip. Prefer flow 2 by returning `embedToken` from your
|
|
715
|
+
* backend alongside `sessionId`.
|
|
716
|
+
* 4. `{ publishableKey }` — client-only; SDK mints a short-lived widget token.
|
|
717
|
+
*/
|
|
808
718
|
async init(config) {
|
|
809
719
|
if (!config) throw new FlonkValidationError("config is required");
|
|
810
720
|
if (config.serverUrl) {
|
|
@@ -818,18 +728,17 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
818
728
|
}
|
|
819
729
|
const pk = config.publishableKey;
|
|
820
730
|
if (!pk || !/^pk_/.test(pk)) {
|
|
821
|
-
throw new FlonkValidationError(
|
|
731
|
+
throw new FlonkValidationError(
|
|
732
|
+
"Provide one of: serverUrl, sessionId + embedToken, or publishableKey (pk_*)"
|
|
733
|
+
);
|
|
822
734
|
}
|
|
823
735
|
return this.initWithPublishableKey(config);
|
|
824
736
|
}
|
|
825
737
|
/**
|
|
826
|
-
|
|
827
|
-
|
|
738
|
+
* Preview mode — no API calls, mock data.
|
|
739
|
+
*/
|
|
828
740
|
preview(config = {}) {
|
|
829
|
-
const colors = config.colors || {
|
|
830
|
-
primaryColor: "#3b82f6",
|
|
831
|
-
secondaryColor: "#93c5fd"
|
|
832
|
-
};
|
|
741
|
+
const colors = config.colors || { primaryColor: "#3b82f6", secondaryColor: "#93c5fd" };
|
|
833
742
|
return this.openWidget({
|
|
834
743
|
mode: "preview",
|
|
835
744
|
isPreview: "true",
|
|
@@ -847,20 +756,17 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
847
756
|
});
|
|
848
757
|
}
|
|
849
758
|
/**
|
|
850
|
-
|
|
851
|
-
|
|
759
|
+
* Embed inline preview in a container (for dashboards).
|
|
760
|
+
*/
|
|
852
761
|
embed(config) {
|
|
853
762
|
if (!config?.container) throw new FlonkValidationError("container is required");
|
|
854
763
|
const container = typeof config.container === "string" ? document.querySelector(config.container) : config.container;
|
|
855
764
|
if (!container) throw new FlonkValidationError("Container element not found");
|
|
856
|
-
let colors = config.colors || {
|
|
857
|
-
primaryColor: "#3b82f6",
|
|
858
|
-
secondaryColor: "#93c5fd"
|
|
859
|
-
};
|
|
765
|
+
let colors = config.colors || { primaryColor: "#3b82f6", secondaryColor: "#93c5fd" };
|
|
860
766
|
let device = config.device || "mobile";
|
|
861
767
|
let scale = config.scale ?? 1;
|
|
862
768
|
const lang = config.lang || "de";
|
|
863
|
-
const buildSrc =
|
|
769
|
+
const buildSrc = (c, d) => {
|
|
864
770
|
const p = new URLSearchParams({
|
|
865
771
|
mode: "preview",
|
|
866
772
|
isPreview: "true",
|
|
@@ -871,11 +777,11 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
871
777
|
lang
|
|
872
778
|
});
|
|
873
779
|
return `${this.widgetUrl}/?${p.toString()}`;
|
|
874
|
-
}
|
|
875
|
-
const applyScale =
|
|
780
|
+
};
|
|
781
|
+
const applyScale = () => {
|
|
876
782
|
iframe.style.transform = scale !== 1 ? `scale(${scale})` : "";
|
|
877
783
|
iframe.style.transformOrigin = scale !== 1 ? "top left" : "";
|
|
878
|
-
}
|
|
784
|
+
};
|
|
879
785
|
const iframe = document.createElement("iframe");
|
|
880
786
|
iframe.style.cssText = "border:none;width:100%;height:100%;display:block";
|
|
881
787
|
iframe.src = buildSrc(colors, device);
|
|
@@ -887,10 +793,7 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
887
793
|
return {
|
|
888
794
|
iframe,
|
|
889
795
|
setColors(newColors) {
|
|
890
|
-
colors = {
|
|
891
|
-
...colors,
|
|
892
|
-
...newColors
|
|
893
|
-
};
|
|
796
|
+
colors = { ...colors, ...newColors };
|
|
894
797
|
if (newColors.primaryColor && !newColors.secondaryColor) {
|
|
895
798
|
colors.secondaryColor = generateSecondaryColor(newColors.primaryColor);
|
|
896
799
|
}
|
|
@@ -900,42 +803,34 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
900
803
|
device = d;
|
|
901
804
|
iframe.src = buildSrc(colors, device);
|
|
902
805
|
},
|
|
903
|
-
getColors:
|
|
904
|
-
|
|
905
|
-
}), "getColors"),
|
|
906
|
-
destroy: /* @__PURE__ */ __name(() => iframe.remove(), "destroy")
|
|
806
|
+
getColors: () => ({ ...colors }),
|
|
807
|
+
destroy: () => iframe.remove()
|
|
907
808
|
};
|
|
908
809
|
}
|
|
909
810
|
// ── Private flows ────────────────────────────────────
|
|
910
811
|
/**
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
812
|
+
* Flow 1: serverUrl — POST to client's backend, get sessionId + embedToken.
|
|
813
|
+
*
|
|
814
|
+
* When `publishableKey` is provided, design tokens are fetched in parallel
|
|
815
|
+
* with the session creation request. This shows the branded loader ~200-500ms
|
|
816
|
+
* faster because we don't have to wait for the session to be created first.
|
|
817
|
+
*/
|
|
917
818
|
async initWithServerUrl(config) {
|
|
918
819
|
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);
|
|
820
|
+
const designTokensPromise = pk ? fetchDesignTokens(this.apiBase, { pk }) : Promise.resolve(null);
|
|
821
|
+
const sessionPromise = fetchSessionFromServer(
|
|
822
|
+
config.serverUrl,
|
|
823
|
+
config.clientMetadata,
|
|
824
|
+
config.requestHeaders
|
|
825
|
+
);
|
|
826
|
+
const { loader, primaryColor } = await showLoaderWithEarlyColor(designTokensPromise, config.lang);
|
|
930
827
|
try {
|
|
931
828
|
const [{ sessionId, embedToken }, designTokens] = await Promise.all([
|
|
932
829
|
sessionPromise,
|
|
933
830
|
designTokensPromise
|
|
934
831
|
]);
|
|
935
|
-
const finalTokens = designTokens ?? await fetchDesignTokens(this.apiBase, {
|
|
936
|
-
|
|
937
|
-
});
|
|
938
|
-
const finalColor = finalTokens?.colors?.primary?.cannabis || "#15BA68";
|
|
832
|
+
const finalTokens = designTokens ?? await fetchDesignTokens(this.apiBase, { sessionId });
|
|
833
|
+
const finalColor = primaryFrom(finalTokens);
|
|
939
834
|
if (finalColor !== primaryColor) loader.updateColor(finalColor);
|
|
940
835
|
const sessionData = await fetchPublicSession(this.apiBase, sessionId, embedToken);
|
|
941
836
|
const session = {
|
|
@@ -959,17 +854,24 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
959
854
|
}
|
|
960
855
|
}
|
|
961
856
|
/**
|
|
962
|
-
|
|
963
|
-
|
|
857
|
+
* Flow 2: sessionId + embedToken — fetch session data, open widget.
|
|
858
|
+
*/
|
|
964
859
|
async initWithEmbedToken(config) {
|
|
965
|
-
const
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
860
|
+
const pk = config.publishableKey;
|
|
861
|
+
const designTokensPromise = pk ? fetchDesignTokens(this.apiBase, { pk }) : fetchDesignTokens(this.apiBase, { sessionId: config.sessionId });
|
|
862
|
+
const sessionPromise = fetchPublicSession(
|
|
863
|
+
this.apiBase,
|
|
864
|
+
config.sessionId,
|
|
865
|
+
config.embedToken
|
|
866
|
+
);
|
|
867
|
+
const { loader, primaryColor } = await showLoaderWithEarlyColor(designTokensPromise, config.lang);
|
|
971
868
|
try {
|
|
972
|
-
const sessionData = await
|
|
869
|
+
const [sessionData, designTokens] = await Promise.all([
|
|
870
|
+
sessionPromise,
|
|
871
|
+
designTokensPromise
|
|
872
|
+
]);
|
|
873
|
+
const finalColor = primaryFrom(designTokens);
|
|
874
|
+
if (finalColor !== primaryColor) loader.updateColor(finalColor);
|
|
973
875
|
const session = {
|
|
974
876
|
id: sessionData.id,
|
|
975
877
|
allowManualUpload: sessionData.allowManualUpload ?? config.allowManualUpload ?? true,
|
|
@@ -991,17 +893,23 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
991
893
|
}
|
|
992
894
|
}
|
|
993
895
|
/**
|
|
994
|
-
|
|
995
|
-
|
|
896
|
+
* Flow 3: sessionId only — exchange for embedToken, then init.
|
|
897
|
+
*
|
|
898
|
+
* @deprecated Prefer flow 2 (`sessionId` + `embedToken`). Return the
|
|
899
|
+
* `embedToken` from your backend together with the `sessionId` to skip this
|
|
900
|
+
* extra token-exchange round-trip.
|
|
901
|
+
*/
|
|
996
902
|
async initWithSession(config) {
|
|
997
|
-
const
|
|
903
|
+
const designTokensPromise = fetchDesignTokens(this.apiBase, {
|
|
998
904
|
sessionId: config.sessionId
|
|
999
905
|
});
|
|
1000
|
-
const
|
|
1001
|
-
const loader =
|
|
1002
|
-
loader.show(primaryColor, config.lang);
|
|
906
|
+
const exchangePromise = exchangeSessionForToken(this.apiBase, config.sessionId);
|
|
907
|
+
const { loader } = await showLoaderWithEarlyColor(designTokensPromise, config.lang);
|
|
1003
908
|
try {
|
|
1004
|
-
const { embedToken, session } = await
|
|
909
|
+
const [{ embedToken, session }, designTokens] = await Promise.all([
|
|
910
|
+
exchangePromise,
|
|
911
|
+
designTokensPromise
|
|
912
|
+
]);
|
|
1005
913
|
return this.buildWidget(embedToken, session, config, loader, designTokens);
|
|
1006
914
|
} catch (err) {
|
|
1007
915
|
const msg = err.message || "Failed to initialize verification";
|
|
@@ -1011,18 +919,15 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
1011
919
|
}
|
|
1012
920
|
}
|
|
1013
921
|
/**
|
|
1014
|
-
|
|
1015
|
-
|
|
922
|
+
* Flow 4: publishableKey — fetch widget token, open widget.
|
|
923
|
+
*/
|
|
1016
924
|
async initWithPublishableKey(config) {
|
|
1017
925
|
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);
|
|
926
|
+
const designTokensPromise = fetchDesignTokens(this.apiBase, { pk });
|
|
927
|
+
const widgetTokenPromise = fetchWidgetToken(pk, this.apiBase);
|
|
928
|
+
const { loader, primaryColor } = await showLoaderWithEarlyColor(designTokensPromise, config.lang);
|
|
1024
929
|
try {
|
|
1025
|
-
const data = await
|
|
930
|
+
const data = await widgetTokenPromise;
|
|
1026
931
|
const params = {
|
|
1027
932
|
mode: "embedded",
|
|
1028
933
|
publishableKey: pk,
|
|
@@ -1077,7 +982,7 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
1077
982
|
if (config.lang) params.lang = config.lang;
|
|
1078
983
|
if (config.overlayColor) params.overlayColor = config.overlayColor;
|
|
1079
984
|
return this.openWidget(params, {
|
|
1080
|
-
primaryColor: designTokens
|
|
985
|
+
primaryColor: primaryFrom(designTokens),
|
|
1081
986
|
lang: config.lang,
|
|
1082
987
|
loader,
|
|
1083
988
|
onSuccess: config.onSuccess,
|
|
@@ -1088,10 +993,12 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
1088
993
|
});
|
|
1089
994
|
}
|
|
1090
995
|
/**
|
|
1091
|
-
|
|
1092
|
-
|
|
996
|
+
* Core: create iframe, attach listeners, return WidgetInstance.
|
|
997
|
+
*/
|
|
1093
998
|
openWidget(params, opts) {
|
|
1094
|
-
const filtered = Object.fromEntries(
|
|
999
|
+
const filtered = Object.fromEntries(
|
|
1000
|
+
Object.entries(params).filter(([, v]) => v != null)
|
|
1001
|
+
);
|
|
1095
1002
|
const search = new URLSearchParams(filtered);
|
|
1096
1003
|
const src = `${this.widgetUrl}/?${search.toString()}`;
|
|
1097
1004
|
const iframe = createIframe(src);
|
|
@@ -1105,7 +1012,7 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
1105
1012
|
mountTarget.appendChild(iframe);
|
|
1106
1013
|
const cleanupViewport = setupViewportSizing(loader.element, iframe);
|
|
1107
1014
|
let cleaned = false;
|
|
1108
|
-
const cleanupAll =
|
|
1015
|
+
const cleanupAll = () => {
|
|
1109
1016
|
if (cleaned) return;
|
|
1110
1017
|
cleaned = true;
|
|
1111
1018
|
try {
|
|
@@ -1115,26 +1022,28 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
1115
1022
|
if (iframe.parentNode) iframe.remove();
|
|
1116
1023
|
} catch {
|
|
1117
1024
|
}
|
|
1118
|
-
}
|
|
1119
|
-
const afterCleanup =
|
|
1025
|
+
};
|
|
1026
|
+
const afterCleanup = (delayMs) => setTimeout(cleanupAll, delayMs);
|
|
1120
1027
|
const handler = new MessageHandler(src, iframe, {
|
|
1121
|
-
onSuccess:
|
|
1028
|
+
onSuccess: (r) => {
|
|
1122
1029
|
opts.onSuccess?.(r);
|
|
1123
|
-
afterCleanup(1e3)
|
|
1124
|
-
}
|
|
1125
|
-
onError:
|
|
1030
|
+
afterCleanup(1e3);
|
|
1031
|
+
},
|
|
1032
|
+
onError: (e) => {
|
|
1126
1033
|
opts.onError?.(e);
|
|
1127
|
-
afterCleanup(500)
|
|
1128
|
-
}
|
|
1129
|
-
onCancel:
|
|
1034
|
+
afterCleanup(500);
|
|
1035
|
+
},
|
|
1036
|
+
onCancel: () => {
|
|
1130
1037
|
opts.onCancel?.();
|
|
1131
|
-
afterCleanup(500)
|
|
1132
|
-
}
|
|
1038
|
+
afterCleanup(500);
|
|
1039
|
+
},
|
|
1133
1040
|
onReady: opts.onReady
|
|
1134
1041
|
});
|
|
1135
1042
|
handler.listen();
|
|
1136
1043
|
handler.onReadyOnce(() => {
|
|
1137
|
-
|
|
1044
|
+
if (loader.element) {
|
|
1045
|
+
transitionLoaderToIframe(loader.element, iframe, () => loader.destroy());
|
|
1046
|
+
}
|
|
1138
1047
|
});
|
|
1139
1048
|
return {
|
|
1140
1049
|
iframe,
|
|
@@ -1142,31 +1051,30 @@ var _FlonkKYC = class _FlonkKYC {
|
|
|
1142
1051
|
};
|
|
1143
1052
|
}
|
|
1144
1053
|
};
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1054
|
+
FlonkKYC.version = SDK_VERSION;
|
|
1055
|
+
function FlonkKYCWidget({
|
|
1056
|
+
widgetUrl,
|
|
1057
|
+
apiBase,
|
|
1058
|
+
autoOpen = true,
|
|
1059
|
+
publishableKey,
|
|
1060
|
+
serverUrl,
|
|
1061
|
+
sessionId,
|
|
1062
|
+
embedToken,
|
|
1063
|
+
clientMetadata,
|
|
1064
|
+
lang,
|
|
1065
|
+
overlayColor,
|
|
1066
|
+
allowManualUpload,
|
|
1067
|
+
requestHeaders,
|
|
1068
|
+
onSuccess,
|
|
1069
|
+
onError,
|
|
1070
|
+
onCancel,
|
|
1071
|
+
onReady
|
|
1072
|
+
}) {
|
|
1149
1073
|
const mountRef = useRef(null);
|
|
1150
1074
|
const widgetRef = useRef(null);
|
|
1151
|
-
const callbacksRef = useRef({
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
onCancel,
|
|
1155
|
-
onReady
|
|
1156
|
-
});
|
|
1157
|
-
callbacksRef.current = {
|
|
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
|
-
]);
|
|
1075
|
+
const callbacksRef = useRef({ onSuccess, onError, onCancel, onReady });
|
|
1076
|
+
callbacksRef.current = { onSuccess, onError, onCancel, onReady };
|
|
1077
|
+
const sdk = useMemo(() => new FlonkKYC({ widgetUrl, apiBase }), [widgetUrl, apiBase]);
|
|
1170
1078
|
const generationRef = useRef(0);
|
|
1171
1079
|
useEffect(() => {
|
|
1172
1080
|
if (!autoOpen) return;
|
|
@@ -1182,10 +1090,10 @@ function FlonkKYCWidget({ widgetUrl, apiBase, autoOpen = true, publishableKey, s
|
|
|
1182
1090
|
allowManualUpload,
|
|
1183
1091
|
requestHeaders,
|
|
1184
1092
|
mount: mountRef.current || void 0,
|
|
1185
|
-
onSuccess:
|
|
1186
|
-
onError:
|
|
1187
|
-
onCancel:
|
|
1188
|
-
onReady:
|
|
1093
|
+
onSuccess: (r) => callbacksRef.current.onSuccess?.(r),
|
|
1094
|
+
onError: (e) => callbacksRef.current.onError?.(e),
|
|
1095
|
+
onCancel: () => callbacksRef.current.onCancel?.(),
|
|
1096
|
+
onReady: () => callbacksRef.current.onReady?.()
|
|
1189
1097
|
};
|
|
1190
1098
|
const timer = setTimeout(() => {
|
|
1191
1099
|
if (generationRef.current !== thisGeneration) return;
|
|
@@ -1206,18 +1114,9 @@ function FlonkKYCWidget({ widgetUrl, apiBase, autoOpen = true, publishableKey, s
|
|
|
1206
1114
|
widgetRef.current?.destroy();
|
|
1207
1115
|
widgetRef.current = null;
|
|
1208
1116
|
};
|
|
1209
|
-
}, [
|
|
1210
|
-
|
|
1211
|
-
publishableKey,
|
|
1212
|
-
serverUrl,
|
|
1213
|
-
sessionId,
|
|
1214
|
-
autoOpen
|
|
1215
|
-
]);
|
|
1216
|
-
return /* @__PURE__ */ React.createElement("div", {
|
|
1217
|
-
ref: mountRef
|
|
1218
|
-
});
|
|
1117
|
+
}, [sdk, publishableKey, serverUrl, sessionId, embedToken, lang, overlayColor, allowManualUpload, autoOpen]);
|
|
1118
|
+
return /* @__PURE__ */ jsx("div", { ref: mountRef });
|
|
1219
1119
|
}
|
|
1220
|
-
__name(FlonkKYCWidget, "FlonkKYCWidget");
|
|
1221
1120
|
|
|
1222
1121
|
export { FlonkError, FlonkKYC, FlonkKYCWidget, FlonkValidationError };
|
|
1223
1122
|
//# sourceMappingURL=index.js.map
|