@youidian/sdk 3.1.1 → 3.2.1

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
@@ -36,7 +36,8 @@ __export(src_exports, {
36
36
  PaymentClient: () => PaymentClient,
37
37
  PaymentUI: () => PaymentUI,
38
38
  createLoginUI: () => createLoginUI,
39
- createPaymentUI: () => createPaymentUI
39
+ createPaymentUI: () => createPaymentUI,
40
+ handleLoginCallbackIfPresent: () => handleLoginCallbackIfPresent
40
41
  });
41
42
  module.exports = __toCommonJS(src_exports);
42
43
 
@@ -237,115 +238,6 @@ var HostedFrameModal = class {
237
238
  }
238
239
  };
239
240
 
240
- // src/client.ts
241
- var PaymentUI = class extends HostedFrameModal {
242
- /**
243
- * Opens the payment checkout page in an iframe modal.
244
- * @param urlOrParams - The checkout page URL or payment parameters
245
- * @param options - UI options
246
- */
247
- openPayment(urlOrParams, options) {
248
- if (typeof document === "undefined") return;
249
- if (this.modal) return;
250
- let checkoutUrl;
251
- if (typeof urlOrParams === "string") {
252
- checkoutUrl = urlOrParams;
253
- } else {
254
- const {
255
- appId,
256
- productId,
257
- priceId,
258
- productCode,
259
- userId,
260
- checkoutUrl: checkoutUrlParam,
261
- baseUrl = "https://pay.imgto.link"
262
- } = urlOrParams;
263
- const base = (checkoutUrlParam || baseUrl).replace(/\/$/, "");
264
- if (productCode) {
265
- checkoutUrl = `${base}/checkout/${appId}/code/${productCode}?userId=${encodeURIComponent(userId)}`;
266
- } else if (productId && priceId) {
267
- checkoutUrl = `${base}/checkout/${appId}/${productId}/${priceId}?userId=${encodeURIComponent(userId)}`;
268
- } else {
269
- throw new Error(
270
- "Either productCode or both productId and priceId are required"
271
- );
272
- }
273
- }
274
- const finalUrl = applyLocaleToUrl(checkoutUrl, options?.locale);
275
- this.openHostedFrame(finalUrl, {
276
- allowedOrigin: options?.allowedOrigin,
277
- onCloseButton: () => options?.onCancel?.(),
278
- onMessage: (data, container) => {
279
- switch (data.type) {
280
- case "PAYMENT_SUCCESS":
281
- options?.onSuccess?.(data.orderId);
282
- break;
283
- case "PAYMENT_CANCELLED":
284
- options?.onCancel?.(data.orderId);
285
- break;
286
- case "PAYMENT_RESIZE":
287
- if (data.height) {
288
- const maxHeight = window.innerHeight * 0.9;
289
- const newHeight = Math.min(data.height, maxHeight);
290
- container.style.height = `${newHeight}px`;
291
- }
292
- break;
293
- case "PAYMENT_CLOSE":
294
- this.close();
295
- options?.onClose?.();
296
- break;
297
- }
298
- }
299
- });
300
- }
301
- /**
302
- * Poll order status from integrator's API endpoint
303
- * @param statusUrl - The integrator's API endpoint to check order status
304
- * @param options - Polling options
305
- * @returns Promise that resolves when order is paid or rejects on timeout/failure
306
- */
307
- async pollOrderStatus(statusUrl, options) {
308
- const interval = options?.interval || 3e3;
309
- const timeout = options?.timeout || 3e5;
310
- const startTime = Date.now();
311
- return new Promise((resolve, reject) => {
312
- const poll = async () => {
313
- try {
314
- const response = await fetch(statusUrl);
315
- if (!response.ok) {
316
- throw new Error(`Status check failed: ${response.status}`);
317
- }
318
- const status = await response.json();
319
- options?.onStatusChange?.(status);
320
- if (status.status === "PAID") {
321
- resolve(status);
322
- return;
323
- }
324
- if (status.status === "CANCELLED" || status.status === "FAILED") {
325
- reject(new Error(`Order ${status.status.toLowerCase()}`));
326
- return;
327
- }
328
- if (Date.now() - startTime > timeout) {
329
- reject(new Error("Polling timeout"));
330
- return;
331
- }
332
- setTimeout(poll, interval);
333
- } catch (error) {
334
- if (Date.now() - startTime > timeout) {
335
- reject(error);
336
- return;
337
- }
338
- setTimeout(poll, interval);
339
- }
340
- };
341
- poll();
342
- });
343
- }
344
- };
345
- function createPaymentUI() {
346
- return new PaymentUI();
347
- }
348
-
349
241
  // src/login.ts
350
242
  function getOrigin(value) {
351
243
  if (!value) return null;
@@ -355,10 +247,33 @@ function getOrigin(value) {
355
247
  return null;
356
248
  }
357
249
  }
358
- function buildLoginLaunchPayload(params, options) {
250
+ function createLoginCallbackState() {
251
+ if (typeof crypto !== "undefined" && crypto.randomUUID) {
252
+ return crypto.randomUUID().replace(/-/g, "");
253
+ }
254
+ return `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
255
+ }
256
+ function buildLoginCallbackUrl(callbackState, callbackUrl) {
257
+ const baseUrl = callbackUrl || window.location.href;
258
+ const url = new URL(baseUrl, window.location.href);
259
+ const returnHash = url.hash.replace(/^#/, "");
260
+ url.hash = "";
261
+ url.searchParams.set(LOGIN_CALLBACK_MARKER, "1");
262
+ url.searchParams.set(LOGIN_CALLBACK_STATE_PARAM, callbackState);
263
+ if (returnHash) {
264
+ url.searchParams.set(LOGIN_CALLBACK_RETURN_HASH_PARAM, returnHash);
265
+ } else {
266
+ url.searchParams.delete(LOGIN_CALLBACK_RETURN_HASH_PARAM);
267
+ }
268
+ return url.toString();
269
+ }
270
+ function buildLoginLaunchPayload(params, options, callbackState) {
359
271
  const parentOrigin = typeof window !== "undefined" ? window.location.origin : void 0;
272
+ const callbackUrl = typeof window !== "undefined" && callbackState ? buildLoginCallbackUrl(callbackState, options?.callbackUrl) : void 0;
360
273
  return {
361
274
  autoClose: options?.autoClose ?? true,
275
+ callbackUrl,
276
+ callbackState,
362
277
  origin: parentOrigin,
363
278
  preferredChannel: params.preferredChannel
364
279
  };
@@ -371,6 +286,9 @@ function appendLoginLaunchHash(urlValue, payload) {
371
286
  if (payload.origin) {
372
287
  hashParams.set("ydOrigin", payload.origin);
373
288
  }
289
+ if (payload.callbackUrl) {
290
+ hashParams.set("ydCallbackUrl", payload.callbackUrl);
291
+ }
374
292
  if (payload.preferredChannel) {
375
293
  hashParams.set("ydPreferredChannel", payload.preferredChannel);
376
294
  }
@@ -389,10 +307,9 @@ function appendLoginLaunchHash(urlValue, payload) {
389
307
  function buildLoginPopupName(payload) {
390
308
  return `youidian-login:${JSON.stringify(payload)}`;
391
309
  }
392
- function buildLoginUrl(params, options) {
310
+ function buildLoginUrl(params, options, launchPayload) {
393
311
  const { appId, baseUrl = "https://pay.imgto.link", loginUrl } = params;
394
312
  const rawBase = (loginUrl || baseUrl).replace(/\/$/, "");
395
- const launchPayload = buildLoginLaunchPayload(params, options);
396
313
  const parentOrigin = launchPayload.origin;
397
314
  let finalUrl;
398
315
  try {
@@ -423,6 +340,9 @@ function buildLoginUrl(params, options) {
423
340
  if (parentOrigin) {
424
341
  url.searchParams.set("origin", parentOrigin);
425
342
  }
343
+ if (launchPayload.callbackUrl) {
344
+ url.searchParams.set("callbackUrl", launchPayload.callbackUrl);
345
+ }
426
346
  return appendLoginLaunchHash(url.toString(), launchPayload);
427
347
  } catch (_error) {
428
348
  const searchParams = new URLSearchParams();
@@ -435,6 +355,9 @@ function buildLoginUrl(params, options) {
435
355
  if (parentOrigin) {
436
356
  searchParams.set("origin", parentOrigin);
437
357
  }
358
+ if (launchPayload.callbackUrl) {
359
+ searchParams.set("callbackUrl", launchPayload.callbackUrl);
360
+ }
438
361
  const query = searchParams.toString();
439
362
  if (!query) {
440
363
  return appendLoginLaunchHash(finalUrl, launchPayload);
@@ -461,6 +384,102 @@ function extractLoginResult(data) {
461
384
  };
462
385
  }
463
386
  var LOGIN_UI_LOG_PREFIX = "[Youidian LoginUI]";
387
+ var LOGIN_CALLBACK_MARKER = "yd_login_callback";
388
+ var LOGIN_CALLBACK_RESULT_PARAM = "yd_login_result";
389
+ var LOGIN_CALLBACK_RETURN_HASH_PARAM = "yd_login_return_hash";
390
+ var LOGIN_CALLBACK_STATE_PARAM = "yd_login_state";
391
+ var LOGIN_CALLBACK_STORAGE_PREFIX = "yd-login-callback:";
392
+ function decodeCallbackPayload(value) {
393
+ try {
394
+ const padded = value.padEnd(
395
+ value.length + (4 - value.length % 4) % 4,
396
+ "="
397
+ );
398
+ const base64 = padded.replaceAll("-", "+").replaceAll("_", "/");
399
+ const binary = atob(base64);
400
+ const json = decodeURIComponent(
401
+ Array.from(
402
+ binary,
403
+ (char) => `%${char.charCodeAt(0).toString(16).padStart(2, "0")}`
404
+ ).join("")
405
+ );
406
+ const parsed = JSON.parse(json);
407
+ return parsed && typeof parsed === "object" && parsed.type ? parsed : null;
408
+ } catch {
409
+ return null;
410
+ }
411
+ }
412
+ function getLoginCallbackChannelName(state) {
413
+ return `youidian-login:${state}`;
414
+ }
415
+ function getLoginCallbackStorageKey(state) {
416
+ return `${LOGIN_CALLBACK_STORAGE_PREFIX}${state}`;
417
+ }
418
+ function publishLoginCallback(state, data) {
419
+ try {
420
+ const channel = new BroadcastChannel(getLoginCallbackChannelName(state));
421
+ channel.postMessage(data);
422
+ channel.close();
423
+ } catch {
424
+ }
425
+ try {
426
+ const storageKey = getLoginCallbackStorageKey(state);
427
+ window.localStorage.setItem(storageKey, JSON.stringify(data));
428
+ window.setTimeout(() => {
429
+ try {
430
+ window.localStorage.removeItem(storageKey);
431
+ } catch {
432
+ }
433
+ }, 800);
434
+ } catch {
435
+ }
436
+ try {
437
+ window.opener?.postMessage(data, window.location.origin);
438
+ } catch {
439
+ }
440
+ }
441
+ function cleanLoginCallbackUrl(url) {
442
+ url.searchParams.delete(LOGIN_CALLBACK_MARKER);
443
+ url.searchParams.delete(LOGIN_CALLBACK_STATE_PARAM);
444
+ const returnHash = url.searchParams.get(LOGIN_CALLBACK_RETURN_HASH_PARAM);
445
+ url.searchParams.delete(LOGIN_CALLBACK_RETURN_HASH_PARAM);
446
+ url.hash = returnHash ? `#${returnHash}` : "";
447
+ return url.toString();
448
+ }
449
+ function handleLoginCallbackIfPresent() {
450
+ if (typeof window === "undefined") {
451
+ return false;
452
+ }
453
+ const url = new URL(window.location.href);
454
+ if (url.searchParams.get(LOGIN_CALLBACK_MARKER) !== "1") {
455
+ return false;
456
+ }
457
+ const state = url.searchParams.get(LOGIN_CALLBACK_STATE_PARAM) || "";
458
+ const hashParams = new URLSearchParams(url.hash.replace(/^#/, ""));
459
+ const rawResult = hashParams.get(LOGIN_CALLBACK_RESULT_PARAM);
460
+ const data = rawResult && state ? decodeCallbackPayload(rawResult) : {
461
+ type: "LOGIN_ERROR",
462
+ message: "Missing login callback result"
463
+ };
464
+ try {
465
+ document.documentElement.style.visibility = "hidden";
466
+ } catch {
467
+ }
468
+ if (state && data) {
469
+ publishLoginCallback(state, data);
470
+ }
471
+ try {
472
+ window.history.replaceState(null, "", cleanLoginCallbackUrl(url));
473
+ } catch {
474
+ }
475
+ window.setTimeout(() => {
476
+ try {
477
+ window.close();
478
+ } catch {
479
+ }
480
+ }, 30);
481
+ return true;
482
+ }
464
483
  function logLoginDebug(message, details) {
465
484
  if (typeof console === "undefined") return;
466
485
  console.debug(LOGIN_UI_LOG_PREFIX, message, details || {});
@@ -476,14 +495,24 @@ function logLoginWarn(message, details) {
476
495
  var LoginUI = class {
477
496
  constructor() {
478
497
  __publicField(this, "popup", null);
498
+ __publicField(this, "callbackChannel", null);
499
+ __publicField(this, "callbackStorageHandler", null);
479
500
  __publicField(this, "messageHandler", null);
480
501
  __publicField(this, "closeMonitor", null);
481
502
  __publicField(this, "completed", false);
482
503
  }
483
504
  cleanup() {
505
+ if (this.callbackChannel) {
506
+ this.callbackChannel.close();
507
+ }
508
+ if (typeof window !== "undefined" && this.callbackStorageHandler) {
509
+ window.removeEventListener("storage", this.callbackStorageHandler);
510
+ }
484
511
  if (typeof window !== "undefined" && this.messageHandler) {
485
512
  window.removeEventListener("message", this.messageHandler);
486
513
  }
514
+ this.callbackChannel = null;
515
+ this.callbackStorageHandler = null;
487
516
  if (typeof window !== "undefined" && this.closeMonitor) {
488
517
  window.clearInterval(this.closeMonitor);
489
518
  }
@@ -492,6 +521,81 @@ var LoginUI = class {
492
521
  this.popup = null;
493
522
  this.completed = false;
494
523
  }
524
+ handleLoginEvent(data, options) {
525
+ if (!data || typeof data !== "object" || !data.type) {
526
+ logLoginDebug("Ignored non-login event payload");
527
+ return;
528
+ }
529
+ logLoginInfo("Received login event", {
530
+ type: data.type
531
+ });
532
+ switch (data.type) {
533
+ case "LOGIN_SUCCESS":
534
+ if (this.completed) {
535
+ break;
536
+ }
537
+ this.completed = true;
538
+ logLoginInfo("Login succeeded", {
539
+ channel: data.channel || null,
540
+ userId: data.userId || null
541
+ });
542
+ options?.onSuccess?.(extractLoginResult(data));
543
+ break;
544
+ case "LOGIN_CANCELLED":
545
+ logLoginInfo("Login cancelled");
546
+ options?.onCancel?.();
547
+ break;
548
+ case "LOGIN_RESIZE":
549
+ break;
550
+ case "LOGIN_ERROR":
551
+ if (this.completed) {
552
+ break;
553
+ }
554
+ logLoginWarn("Login flow reported an error", {
555
+ message: data.message || data.error || null
556
+ });
557
+ options?.onError?.(data.message || data.error, data);
558
+ break;
559
+ case "LOGIN_CLOSE":
560
+ if (options?.autoClose === false) {
561
+ logLoginInfo(
562
+ "Login popup requested close; autoClose disabled, keeping popup open"
563
+ );
564
+ options?.onClose?.();
565
+ break;
566
+ }
567
+ logLoginInfo("Login popup requested close; autoClose enabled");
568
+ this.close();
569
+ options?.onClose?.();
570
+ break;
571
+ }
572
+ }
573
+ listenForLoginCallback(callbackState, options) {
574
+ try {
575
+ this.callbackChannel = new BroadcastChannel(
576
+ getLoginCallbackChannelName(callbackState)
577
+ );
578
+ this.callbackChannel.onmessage = (event) => {
579
+ this.handleLoginEvent(event.data, options);
580
+ this.handleLoginEvent({ type: "LOGIN_CLOSE" }, options);
581
+ };
582
+ } catch {
583
+ logLoginDebug("BroadcastChannel is unavailable for login callback");
584
+ }
585
+ this.callbackStorageHandler = (event) => {
586
+ if (event.key !== getLoginCallbackStorageKey(callbackState) || !event.newValue) {
587
+ return;
588
+ }
589
+ try {
590
+ const data = JSON.parse(event.newValue);
591
+ this.handleLoginEvent(data, options);
592
+ this.handleLoginEvent({ type: "LOGIN_CLOSE" }, options);
593
+ } catch {
594
+ logLoginWarn("Failed to parse login callback storage payload");
595
+ }
596
+ };
597
+ window.addEventListener("storage", this.callbackStorageHandler);
598
+ }
495
599
  close() {
496
600
  logLoginInfo("close() called", {
497
601
  hasPopup: Boolean(this.popup),
@@ -505,12 +609,23 @@ var LoginUI = class {
505
609
  openLogin(params, options) {
506
610
  if (typeof window === "undefined") return;
507
611
  if (this.popup && !this.popup.closed) return;
508
- const finalUrl = buildLoginUrl(params, options);
612
+ const callbackState = createLoginCallbackState();
613
+ const launchPayload = buildLoginLaunchPayload(
614
+ params,
615
+ options,
616
+ callbackState
617
+ );
618
+ const finalUrl = buildLoginUrl(params, options, launchPayload);
509
619
  logLoginInfo("Opening hosted login popup", {
510
620
  appId: params.appId,
621
+ callbackState,
622
+ callbackUrl: launchPayload.callbackUrl || null,
623
+ hasCallbackUrl: Boolean(launchPayload.callbackUrl),
511
624
  loginUrl: finalUrl,
512
625
  allowedOrigin: options?.allowedOrigin || null,
513
- autoClose: options?.autoClose ?? true
626
+ autoClose: options?.autoClose ?? true,
627
+ pageUrl: typeof window !== "undefined" ? window.location.href : null,
628
+ parentOrigin: launchPayload.origin || null
514
629
  });
515
630
  const popupWidth = 520;
516
631
  const popupHeight = 720;
@@ -531,9 +646,7 @@ var LoginUI = class {
531
646
  "resizable=yes",
532
647
  "scrollbars=yes"
533
648
  ].join(",");
534
- const popupName = buildLoginPopupName(
535
- buildLoginLaunchPayload(params, options)
536
- );
649
+ const popupName = buildLoginPopupName(launchPayload);
537
650
  const popup = window.open(finalUrl, popupName, features);
538
651
  if (!popup) {
539
652
  logLoginWarn("Popup blocked by the browser");
@@ -542,6 +655,7 @@ var LoginUI = class {
542
655
  }
543
656
  this.popup = popup;
544
657
  this.completed = false;
658
+ this.listenForLoginCallback(callbackState, options);
545
659
  const allowedOrigin = options?.allowedOrigin;
546
660
  const popupOrigin = getOrigin(finalUrl);
547
661
  this.messageHandler = (event) => {
@@ -568,40 +682,7 @@ var LoginUI = class {
568
682
  type: data.type,
569
683
  eventOrigin: event.origin
570
684
  });
571
- switch (data.type) {
572
- case "LOGIN_SUCCESS":
573
- this.completed = true;
574
- logLoginInfo("Login succeeded", {
575
- channel: data.channel || null,
576
- userId: data.userId || null
577
- });
578
- options?.onSuccess?.(extractLoginResult(data));
579
- break;
580
- case "LOGIN_CANCELLED":
581
- logLoginInfo("Login cancelled");
582
- options?.onCancel?.();
583
- break;
584
- case "LOGIN_RESIZE":
585
- break;
586
- case "LOGIN_ERROR":
587
- logLoginWarn("Login flow reported an error", {
588
- message: data.message || data.error || null
589
- });
590
- options?.onError?.(data.message || data.error, data);
591
- break;
592
- case "LOGIN_CLOSE":
593
- if (options?.autoClose === false) {
594
- logLoginInfo(
595
- "Login popup requested close; autoClose disabled, keeping popup open"
596
- );
597
- options?.onClose?.();
598
- break;
599
- }
600
- logLoginInfo("Login popup requested close; autoClose enabled");
601
- this.close();
602
- options?.onClose?.();
603
- break;
604
- }
685
+ this.handleLoginEvent(data, options);
605
686
  };
606
687
  window.addEventListener("message", this.messageHandler);
607
688
  this.closeMonitor = window.setInterval(() => {
@@ -622,6 +703,116 @@ var LoginUI = class {
622
703
  function createLoginUI() {
623
704
  return new LoginUI();
624
705
  }
706
+ handleLoginCallbackIfPresent();
707
+
708
+ // src/client.ts
709
+ var PaymentUI = class extends HostedFrameModal {
710
+ /**
711
+ * Opens the payment checkout page in an iframe modal.
712
+ * @param urlOrParams - The checkout page URL or payment parameters
713
+ * @param options - UI options
714
+ */
715
+ openPayment(urlOrParams, options) {
716
+ if (typeof document === "undefined") return;
717
+ if (this.modal) return;
718
+ let checkoutUrl;
719
+ if (typeof urlOrParams === "string") {
720
+ checkoutUrl = urlOrParams;
721
+ } else {
722
+ const {
723
+ appId,
724
+ productId,
725
+ priceId,
726
+ productCode,
727
+ userId,
728
+ checkoutUrl: checkoutUrlParam,
729
+ baseUrl = "https://pay.imgto.link"
730
+ } = urlOrParams;
731
+ const base = (checkoutUrlParam || baseUrl).replace(/\/$/, "");
732
+ if (productCode) {
733
+ checkoutUrl = `${base}/checkout/${appId}/code/${productCode}?userId=${encodeURIComponent(userId)}`;
734
+ } else if (productId && priceId) {
735
+ checkoutUrl = `${base}/checkout/${appId}/${productId}/${priceId}?userId=${encodeURIComponent(userId)}`;
736
+ } else {
737
+ throw new Error(
738
+ "Either productCode or both productId and priceId are required"
739
+ );
740
+ }
741
+ }
742
+ const finalUrl = applyLocaleToUrl(checkoutUrl, options?.locale);
743
+ this.openHostedFrame(finalUrl, {
744
+ allowedOrigin: options?.allowedOrigin,
745
+ onCloseButton: () => options?.onCancel?.(),
746
+ onMessage: (data, container) => {
747
+ switch (data.type) {
748
+ case "PAYMENT_SUCCESS":
749
+ options?.onSuccess?.(data.orderId);
750
+ break;
751
+ case "PAYMENT_CANCELLED":
752
+ options?.onCancel?.(data.orderId);
753
+ break;
754
+ case "PAYMENT_RESIZE":
755
+ if (data.height) {
756
+ const maxHeight = window.innerHeight * 0.9;
757
+ const newHeight = Math.min(data.height, maxHeight);
758
+ container.style.height = `${newHeight}px`;
759
+ }
760
+ break;
761
+ case "PAYMENT_CLOSE":
762
+ this.close();
763
+ options?.onClose?.();
764
+ break;
765
+ }
766
+ }
767
+ });
768
+ }
769
+ /**
770
+ * Poll order status from integrator's API endpoint
771
+ * @param statusUrl - The integrator's API endpoint to check order status
772
+ * @param options - Polling options
773
+ * @returns Promise that resolves when order is paid or rejects on timeout/failure
774
+ */
775
+ async pollOrderStatus(statusUrl, options) {
776
+ const interval = options?.interval || 3e3;
777
+ const timeout = options?.timeout || 3e5;
778
+ const startTime = Date.now();
779
+ return new Promise((resolve, reject) => {
780
+ const poll = async () => {
781
+ try {
782
+ const response = await fetch(statusUrl);
783
+ if (!response.ok) {
784
+ throw new Error(`Status check failed: ${response.status}`);
785
+ }
786
+ const status = await response.json();
787
+ options?.onStatusChange?.(status);
788
+ if (status.status === "PAID") {
789
+ resolve(status);
790
+ return;
791
+ }
792
+ if (status.status === "CANCELLED" || status.status === "FAILED") {
793
+ reject(new Error(`Order ${status.status.toLowerCase()}`));
794
+ return;
795
+ }
796
+ if (Date.now() - startTime > timeout) {
797
+ reject(new Error("Polling timeout"));
798
+ return;
799
+ }
800
+ setTimeout(poll, interval);
801
+ } catch (error) {
802
+ if (Date.now() - startTime > timeout) {
803
+ reject(error);
804
+ return;
805
+ }
806
+ setTimeout(poll, interval);
807
+ }
808
+ };
809
+ poll();
810
+ });
811
+ }
812
+ };
813
+ function createPaymentUI() {
814
+ return new PaymentUI();
815
+ }
625
816
 
626
817
  // src/server.ts
627
818
  var import_crypto = __toESM(require("crypto"), 1);
@@ -879,6 +1070,7 @@ var PaymentClient = class {
879
1070
  PaymentClient,
880
1071
  PaymentUI,
881
1072
  createLoginUI,
882
- createPaymentUI
1073
+ createPaymentUI,
1074
+ handleLoginCallbackIfPresent
883
1075
  });
884
1076
  //# sourceMappingURL=index.cjs.map