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