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