@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/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.6.0";
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 _FlonkError = class _FlonkError extends Error {
16
+ var FlonkError = class extends Error {
21
17
  constructor(message, code, statusCode) {
22
18
  super(message);
23
- __publicField(this, "code");
24
- __publicField(this, "statusCode");
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
- __name(_FlonkError, "FlonkError");
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 window.location.origin;
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 = /* @__PURE__ */ __name((n) => {
67
+ const toHex = (n) => {
82
68
  const s = n.toString(16);
83
69
  return s.length === 1 ? "0" + s : s;
84
- }, "toHex");
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
- __name(generateSecondaryColor, "generateSecondaryColor");
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 fetch(`${apiBase}/public/widget-token`, {
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
- __name(fetchWidgetToken, "fetchWidgetToken");
110
- async function fetchDesignTokens(apiBase, opts) {
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
- try {
116
- const res = await fetch(url, {
117
- headers: opts.pk ? {
118
- "x-kyc-pk": opts.pk
119
- } : {},
120
- credentials: "omit"
121
- });
122
- return res.ok ? res.json() : null;
123
- } catch {
124
- return null;
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(`serverUrl must use HTTPS in production. Got: ${parsed.protocol}//. Use HTTPS ('https://api.myapp.com/...') or a relative path ('/api/...')`);
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 fetch(serverUrl, {
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 fetch(`${apiBase}/public/session/${sessionId}`, {
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 fetch(`${apiBase}/public/session/${sessionId}/token`, {
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("iframe", {
211
- border: "0",
212
- width: window.innerWidth + "px",
213
- height: window.innerHeight + "px",
214
- position: "fixed",
215
- top: "0",
216
- left: "0",
217
- zIndex: "9999",
218
- background: "transparent",
219
- backgroundColor: "transparent",
220
- opacity: "0",
221
- visibility: "hidden",
222
- borderRadius: d ? "0" : "",
223
- boxShadow: d ? "none" : "",
224
- colorScheme: "normal"
225
- }, {
226
- src,
227
- allow: "camera;microphone;clipboard-read;clipboard-write",
228
- sandbox: "allow-scripts allow-forms allow-same-origin allow-popups",
229
- "aria-label": "KYC Verification",
230
- allowtransparency: "true"
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(...all.map((el) => parseInt(getComputedStyle(el).zIndex) || 0).filter((z) => z < 999999));
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
- title: "Initializing...",
281
- subtitle: "Loading KYC widget",
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 _Loader = class _Loader {
297
+ var Loader = class {
305
298
  constructor() {
306
- __publicField(this, "overlay", null);
307
- __publicField(this, "cleanup", null);
308
- __publicField(this, "origBodyStyles", null);
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
- textAlign: "center"
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
- width: "100%",
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
- overflow: document.body.style.overflow,
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 _MessageHandler = class _MessageHandler {
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
- * Start listening for postMessage events from the widget iframe.
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 && this.callbacks.onSuccess) {
555
+ if (type === WIDGET_EVENTS.COMPLETE) {
616
556
  if (this.completionHandled) return;
617
557
  this.completionHandled = true;
618
- this.callbacks.onSuccess(data.result);
619
- setTimeout(() => this.iframe.remove(), 1e3);
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
- setTimeout(() => this.iframe.remove(), 500);
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
- setTimeout(() => this.iframe.remove(), 500);
630
- } else if (type === WIDGET_EVENTS.READY && this.callbacks.onReady) {
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
- * Listen for the first READY event, then call the callback once.
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) return;
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 = /* @__PURE__ */ __name(() => {
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
- }, "initBaseline");
711
- const applySize = /* @__PURE__ */ __name(() => {
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
- }, "applySize");
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 = /* @__PURE__ */ __name(() => {
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
- }, "handleResize");
762
- const handleOrientation = /* @__PURE__ */ __name(() => {
681
+ };
682
+ const handleOrientation = () => {
763
683
  initBaseline();
764
684
  if (rafId) cancelAnimationFrame(rafId);
765
685
  rafId = requestAnimationFrame(applySize);
766
- }, "handleOrientation");
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 _FlonkKYC = class _FlonkKYC {
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
- * Open the KYC verification widget.
801
- *
802
- * Flows (pick one):
803
- * 1. `{ serverUrl, publishableKey }` — auto-create session via your backend (recommended).
804
- * `publishableKey` enables instant branded loader (~200-500ms faster).
805
- * 2. `{ sessionId, embedToken }` — server-to-server with pre-created session
806
- * 3. `{ publishableKey }` client-side only (legacy)
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("Provide one of: serverUrl, sessionId + embedToken, or publishableKey (pk_*)");
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
- * Preview mode — no API calls, mock data.
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
- * Embed inline preview in a container (for dashboards).
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 = /* @__PURE__ */ __name((c, d) => {
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
- }, "buildSrc");
875
- const applyScale = /* @__PURE__ */ __name(() => {
822
+ };
823
+ const applyScale = () => {
876
824
  iframe.style.transform = scale !== 1 ? `scale(${scale})` : "";
877
825
  iframe.style.transformOrigin = scale !== 1 ? "top left" : "";
878
- }, "applyScale");
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: /* @__PURE__ */ __name(() => ({
904
- ...colors
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
- * Flow 1: serverUrl — POST to client's backend, get sessionId + embedToken.
912
- *
913
- * When `publishableKey` is provided, design tokens are fetched in parallel
914
- * with the session creation request. This shows the branded loader ~200-500ms
915
- * faster because we don't have to wait for the session to be created first.
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
- pk
921
- }) : Promise.resolve(null);
922
- const sessionPromise = fetchSessionFromServer(config.serverUrl, config.clientMetadata, config.requestHeaders);
923
- const earlyTokens = await Promise.race([
924
- designTokensPromise,
925
- new Promise((resolve) => setTimeout(() => resolve(null), 800))
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
- sessionId
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
- * Flow 2: sessionId + embedToken — fetch session data, open widget.
963
- */
899
+ * Flow 2: sessionId + embedToken — fetch session data, open widget.
900
+ */
964
901
  async initWithEmbedToken(config) {
965
- const designTokens = await fetchDesignTokens(this.apiBase, {
966
- sessionId: config.sessionId
967
- });
968
- const primaryColor = designTokens?.colors?.primary?.cannabis || "#15BA68";
969
- const loader = new Loader();
970
- loader.show(primaryColor, config.lang);
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 fetchPublicSession(this.apiBase, config.sessionId, config.embedToken);
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
- * Flow 3: sessionId only — exchange for embedToken, then init.
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 designTokens = await fetchDesignTokens(this.apiBase, {
945
+ const designTokensPromise = fetchDesignTokens(this.apiBase, {
998
946
  sessionId: config.sessionId
999
947
  });
1000
- const primaryColor = designTokens?.colors?.primary?.cannabis || "#15BA68";
1001
- const loader = new 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 exchangeSessionForToken(this.apiBase, config.sessionId);
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
- * Flow 4: publishableKey — fetch widget token, open widget.
1015
- */
964
+ * Flow 4: publishableKey — fetch widget token, open widget.
965
+ */
1016
966
  async initWithPublishableKey(config) {
1017
967
  const pk = config.publishableKey;
1018
- const designTokens = await fetchDesignTokens(this.apiBase, {
1019
- pk
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 fetchWidgetToken(pk, this.apiBase);
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?.colors?.primary?.cannabis || "#15BA68",
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
- * Core: create iframe, attach listeners, return WidgetInstance.
1092
- */
1038
+ * Core: create iframe, attach listeners, return WidgetInstance.
1039
+ */
1093
1040
  openWidget(params, opts) {
1094
- const filtered = Object.fromEntries(Object.entries(params).filter(([, v]) => v != null));
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 = /* @__PURE__ */ __name(() => {
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
- }, "cleanupAll");
1119
- const afterCleanup = /* @__PURE__ */ __name((delayMs) => () => setTimeout(cleanupAll, delayMs), "afterCleanup");
1067
+ };
1068
+ const afterCleanup = (delayMs) => setTimeout(cleanupAll, delayMs);
1120
1069
  const handler = new MessageHandler(src, iframe, {
1121
- onSuccess: opts.onSuccess ? (r) => {
1070
+ onSuccess: (r) => {
1122
1071
  opts.onSuccess?.(r);
1123
- afterCleanup(1e3)();
1124
- } : void 0,
1125
- onError: opts.onError ? (e) => {
1072
+ afterCleanup(1e3);
1073
+ },
1074
+ onError: (e) => {
1126
1075
  opts.onError?.(e);
1127
- afterCleanup(500)();
1128
- } : void 0,
1129
- onCancel: opts.onCancel ? () => {
1076
+ afterCleanup(500);
1077
+ },
1078
+ onCancel: () => {
1130
1079
  opts.onCancel?.();
1131
- afterCleanup(500)();
1132
- } : void 0,
1080
+ afterCleanup(500);
1081
+ },
1133
1082
  onReady: opts.onReady
1134
1083
  });
1135
1084
  handler.listen();
1136
1085
  handler.onReadyOnce(() => {
1137
- transitionLoaderToIframe(loader.element, iframe, () => loader.destroy());
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
- __name(_FlonkKYC, "FlonkKYC");
1146
- __publicField(_FlonkKYC, "version", SDK_VERSION);
1147
- var FlonkKYC = _FlonkKYC;
1148
- function FlonkKYCWidget({ widgetUrl, apiBase, autoOpen = true, publishableKey, serverUrl, sessionId, embedToken, clientMetadata, lang, overlayColor, allowManualUpload, requestHeaders, onSuccess, onError, onCancel, onReady }) {
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
- onSuccess,
1153
- onError,
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
- ]);
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: /* @__PURE__ */ __name((r) => callbacksRef.current.onSuccess?.(r), "onSuccess"),
1186
- onError: /* @__PURE__ */ __name((e) => callbacksRef.current.onError?.(e), "onError"),
1187
- onCancel: /* @__PURE__ */ __name(() => callbacksRef.current.onCancel?.(), "onCancel"),
1188
- onReady: /* @__PURE__ */ __name(() => callbacksRef.current.onReady?.(), "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
- sdk,
1211
- publishableKey,
1212
- serverUrl,
1213
- sessionId,
1214
- autoOpen
1215
- ]);
1216
- return /* @__PURE__ */ React.createElement("div", {
1217
- ref: mountRef
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