@swype-org/deposit 0.3.16 → 0.3.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/{chunk-WD6DVQHT.js → chunk-VMXCXXVN.js} +202 -23
- package/dist/chunk-VMXCXXVN.js.map +1 -0
- package/dist/index.cjs +200 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +39 -3
- package/dist/index.d.ts +39 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +313 -20
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +34 -3
- package/dist/react.d.ts +34 -3
- package/dist/react.js +119 -4
- package/dist/react.js.map +1 -1
- package/dist/{types-DYsZwNXq.d.cts → types-Ds07N2zN.d.cts} +44 -1
- package/dist/{types-DYsZwNXq.d.ts → types-Ds07N2zN.d.ts} +44 -1
- package/package.json +6 -3
- package/dist/chunk-WD6DVQHT.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { D as DepositStatus, a as DepositResult, b as DepositError, c as DepositConfig, d as DepositRequest } from './types-
|
|
2
|
-
export { C as CheckoutConfig, e as CheckoutError, f as CheckoutErrorCode, g as CheckoutStatus, h as DepositErrorCode, S as SignerFunction, i as SignerRequest, j as SignerResponse, T as TransferSummary, k as getDisplayMessage } from './types-
|
|
1
|
+
import { D as DepositStatus, a as DepositResult, b as DepositError, c as DepositConfig, d as DepositRequest } from './types-Ds07N2zN.js';
|
|
2
|
+
export { C as CheckoutConfig, e as CheckoutError, f as CheckoutErrorCode, g as CheckoutStatus, h as DepositErrorCode, S as SignerFunction, i as SignerRequest, j as SignerResponse, T as TransferSummary, k as getDisplayMessage } from './types-Ds07N2zN.js';
|
|
3
3
|
|
|
4
4
|
declare const DEFAULT_WEBVIEW_BASE_URL = "https://pay.blink.cash";
|
|
5
|
+
declare const SANDBOX_WEBVIEW_BASE_URL = "https://pay-sandbox.blink.cash";
|
|
5
6
|
type EventMap = {
|
|
6
7
|
complete: (result: DepositResult) => void;
|
|
7
8
|
error: (error: DepositError) => void;
|
|
@@ -36,6 +37,9 @@ declare class Deposit {
|
|
|
36
37
|
private _error;
|
|
37
38
|
private flowTimer;
|
|
38
39
|
private lastSignerResponse;
|
|
40
|
+
private warmIframe;
|
|
41
|
+
private warmIframeReady;
|
|
42
|
+
private warmIframeReadyCancel;
|
|
39
43
|
private listeners;
|
|
40
44
|
/** Current phase of the deposit flow. */
|
|
41
45
|
get status(): DepositStatus;
|
|
@@ -46,6 +50,25 @@ declare class Deposit {
|
|
|
46
50
|
/** Whether a deposit flow is currently in progress (signer loading or iframe open). */
|
|
47
51
|
get isActive(): boolean;
|
|
48
52
|
constructor(config: DepositConfig);
|
|
53
|
+
/**
|
|
54
|
+
* Warm up the hosted payment flow in a hidden iframe so `requestDeposit`
|
|
55
|
+
* opens an already-loaded page (JS bundle, auth session restore, and —
|
|
56
|
+
* when {@link DepositConfig.merchantId} is set — merchant config prefetch
|
|
57
|
+
* all happen in the background).
|
|
58
|
+
*
|
|
59
|
+
* Runs automatically after construction unless `preload: false`; call it
|
|
60
|
+
* manually to control the timing (e.g. on deposit-button hover). No-op
|
|
61
|
+
* when a warm iframe already exists or a deposit flow is active.
|
|
62
|
+
*/
|
|
63
|
+
preload(): void;
|
|
64
|
+
private schedulePreload;
|
|
65
|
+
private buildPreloadUrl;
|
|
66
|
+
/**
|
|
67
|
+
* Detach the warm iframe for use by a starting flow. Returns null (and
|
|
68
|
+
* cleans up) when there is none or it was closed in the meantime.
|
|
69
|
+
*/
|
|
70
|
+
private takeWarmIframe;
|
|
71
|
+
private discardWarmIframe;
|
|
49
72
|
/**
|
|
50
73
|
* Open the hosted payment flow for the given deposit.
|
|
51
74
|
*
|
|
@@ -64,8 +87,21 @@ declare class Deposit {
|
|
|
64
87
|
/** Tear down the instance and release all resources. */
|
|
65
88
|
destroy(): void;
|
|
66
89
|
private log;
|
|
90
|
+
/**
|
|
91
|
+
* Appends `enableFullWidget=false` to the hosted-flow URL when the merchant
|
|
92
|
+
* integration disables the full widget. Absence of the param means enabled
|
|
93
|
+
* (the default) — the hosted flow ANDs this with the merchant's backend
|
|
94
|
+
* config, so the full widget renders only when both allow it.
|
|
95
|
+
*/
|
|
96
|
+
private applyFullWidgetParam;
|
|
67
97
|
private setStatus;
|
|
68
98
|
private runSignerFlow;
|
|
99
|
+
/**
|
|
100
|
+
* Resolves true when the iframe posts `blink:iframe-ready`, false on
|
|
101
|
+
* timeout. `cancel()` settles the promise as false immediately and releases
|
|
102
|
+
* the listener + timer — used to reap the generous warm-up wait once it no
|
|
103
|
+
* longer matters (warm iframe consumed or discarded).
|
|
104
|
+
*/
|
|
69
105
|
private waitForIframeReady;
|
|
70
106
|
private startMessageListener;
|
|
71
107
|
private cleanup;
|
|
@@ -232,4 +268,4 @@ declare function attachRpcHost(options: RpcHostOptions): RpcHostHandle;
|
|
|
232
268
|
|
|
233
269
|
declare const VERSION = "0.3.0";
|
|
234
270
|
|
|
235
|
-
export { ALLOWED_RPC_METHODS, type AdvertisedWallet, BRIDGE_PROTOCOL_VERSION, type EIP1193Provider as BridgeEIP1193Provider, type BridgeHelloMessage, type BridgeMessage, Checkout, DEFAULT_WEBVIEW_BASE_URL, Deposit, DepositConfig, DepositError, DepositRequest, DepositResult, DepositStatus, type EIP6963ProviderDetail, type EIP6963ProviderInfo, type RegisteredProvider, type RpcEventMessage, type RpcHostHandle, type RpcHostOptions, type RpcRequestMessage, type RpcResponseMessage, VERSION, type WalletDiscovererHandle, type WalletsAdvertisedMessage, attachRpcHost, createWalletDiscoverer, parseBridgeMessage };
|
|
271
|
+
export { ALLOWED_RPC_METHODS, type AdvertisedWallet, BRIDGE_PROTOCOL_VERSION, type EIP1193Provider as BridgeEIP1193Provider, type BridgeHelloMessage, type BridgeMessage, Checkout, DEFAULT_WEBVIEW_BASE_URL, Deposit, DepositConfig, DepositError, DepositRequest, DepositResult, DepositStatus, type EIP6963ProviderDetail, type EIP6963ProviderInfo, type RegisteredProvider, type RpcEventMessage, type RpcHostHandle, type RpcHostOptions, type RpcRequestMessage, type RpcResponseMessage, SANDBOX_WEBVIEW_BASE_URL, VERSION, type WalletDiscovererHandle, type WalletsAdvertisedMessage, attachRpcHost, createWalletDiscoverer, parseBridgeMessage };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ALLOWED_RPC_METHODS, BRIDGE_PROTOCOL_VERSION, Checkout, CheckoutError, DEFAULT_WEBVIEW_BASE_URL, Deposit, DepositError, attachRpcHost, createWalletDiscoverer, getDisplayMessage, parseBridgeMessage } from './chunk-
|
|
1
|
+
export { ALLOWED_RPC_METHODS, BRIDGE_PROTOCOL_VERSION, Checkout, CheckoutError, DEFAULT_WEBVIEW_BASE_URL, Deposit, DepositError, SANDBOX_WEBVIEW_BASE_URL, attachRpcHost, createWalletDiscoverer, getDisplayMessage, parseBridgeMessage } from './chunk-VMXCXXVN.js';
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
var VERSION = "0.3.0";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;AA2CO,IAAM,OAAA,GAAU","file":"index.js","sourcesContent":["export { Deposit, Checkout, DEFAULT_WEBVIEW_BASE_URL } from './checkout.ts';\nexport { DepositError, CheckoutError, getDisplayMessage } from './errors.ts';\nexport type { DepositErrorCode, CheckoutErrorCode } from './errors.ts';\nexport type {\n DepositConfig,\n CheckoutConfig,\n DepositStatus,\n CheckoutStatus,\n DepositRequest,\n DepositResult,\n SignerFunction,\n SignerRequest,\n SignerResponse,\n TransferSummary,\n} from './types.ts';\n\n// ── Wallet bridge (advanced) ──────────────────────────────────────────\n// Internal building blocks for the top-frame → iframe wallet bridge.\n// Default merchant integrations don't need these — `createIframe()` wires\n// them automatically. Re-exported so monorepo tests and any merchant\n// custom-iframe wrapper can poke at the protocol shapes.\nexport { createWalletDiscoverer } from './walletBridge/discover.ts';\nexport type { WalletDiscovererHandle, RegisteredProvider } from './walletBridge/discover.ts';\nexport { attachRpcHost } from './walletBridge/rpcHost.ts';\nexport type { RpcHostHandle, RpcHostOptions } from './walletBridge/rpcHost.ts';\nexport {\n ALLOWED_RPC_METHODS,\n BRIDGE_PROTOCOL_VERSION,\n parseBridgeMessage,\n} from './walletBridge/protocol.ts';\nexport type {\n AdvertisedWallet,\n BridgeMessage,\n BridgeHelloMessage,\n WalletsAdvertisedMessage,\n RpcRequestMessage,\n RpcResponseMessage,\n RpcEventMessage,\n EIP1193Provider as BridgeEIP1193Provider,\n EIP6963ProviderInfo,\n EIP6963ProviderDetail,\n} from './walletBridge/protocol.ts';\n\nexport const VERSION = '0.3.0';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":";;;AA2CO,IAAM,OAAA,GAAU","file":"index.js","sourcesContent":["export { Deposit, Checkout, DEFAULT_WEBVIEW_BASE_URL, SANDBOX_WEBVIEW_BASE_URL } from './checkout.ts';\nexport { DepositError, CheckoutError, getDisplayMessage } from './errors.ts';\nexport type { DepositErrorCode, CheckoutErrorCode } from './errors.ts';\nexport type {\n DepositConfig,\n CheckoutConfig,\n DepositStatus,\n CheckoutStatus,\n DepositRequest,\n DepositResult,\n SignerFunction,\n SignerRequest,\n SignerResponse,\n TransferSummary,\n} from './types.ts';\n\n// ── Wallet bridge (advanced) ──────────────────────────────────────────\n// Internal building blocks for the top-frame → iframe wallet bridge.\n// Default merchant integrations don't need these — `createIframe()` wires\n// them automatically. Re-exported so monorepo tests and any merchant\n// custom-iframe wrapper can poke at the protocol shapes.\nexport { createWalletDiscoverer } from './walletBridge/discover.ts';\nexport type { WalletDiscovererHandle, RegisteredProvider } from './walletBridge/discover.ts';\nexport { attachRpcHost } from './walletBridge/rpcHost.ts';\nexport type { RpcHostHandle, RpcHostOptions } from './walletBridge/rpcHost.ts';\nexport {\n ALLOWED_RPC_METHODS,\n BRIDGE_PROTOCOL_VERSION,\n parseBridgeMessage,\n} from './walletBridge/protocol.ts';\nexport type {\n AdvertisedWallet,\n BridgeMessage,\n BridgeHelloMessage,\n WalletsAdvertisedMessage,\n RpcRequestMessage,\n RpcResponseMessage,\n RpcEventMessage,\n EIP1193Provider as BridgeEIP1193Provider,\n EIP6963ProviderInfo,\n EIP6963ProviderDetail,\n} from './walletBridge/protocol.ts';\n\nexport const VERSION = '0.3.0';\n"]}
|
package/dist/react.cjs
CHANGED
|
@@ -529,15 +529,19 @@ var STYLES = `
|
|
|
529
529
|
[data-blink-overlay][data-blink-mobile-sheet][data-blink-closing] [data-blink-container]{opacity:1;animation:blink-slide-down-full ${CLOSE_DURATION_MS}ms ease-in forwards}
|
|
530
530
|
@media(max-width:${MOBILE_SHEET_MAX_VIEWPORT_PX}px){[data-blink-overlay]{align-items:flex-end;touch-action:none;overscroll-behavior:contain}[data-blink-container]{width:100%;max-width:100%;height:79vh;border-radius:24px 24px 0 0;box-shadow:0 -8px 40px rgba(0,0,0,.25);animation:blink-slide-up-full .35s cubic-bezier(.32,.72,0,1);padding-bottom:env(safe-area-inset-bottom,0px)}[data-blink-overlay][data-blink-closing] [data-blink-container]{opacity:1;animation:blink-slide-down-full ${CLOSE_DURATION_MS}ms ease-in forwards}}
|
|
531
531
|
`;
|
|
532
|
-
function createIframe(url, containerElement) {
|
|
532
|
+
function createIframe(url, containerElement, options) {
|
|
533
533
|
ensureStyles();
|
|
534
534
|
let closed = false;
|
|
535
|
+
let hidden = options?.hidden === true;
|
|
535
536
|
let closeCallback = null;
|
|
536
537
|
const overlay = document.createElement("div");
|
|
537
538
|
overlay.setAttribute("data-blink-overlay", "");
|
|
538
539
|
if (shouldUseMobileSheetLayout()) {
|
|
539
540
|
overlay.setAttribute("data-blink-mobile-sheet", "");
|
|
540
541
|
}
|
|
542
|
+
if (hidden) {
|
|
543
|
+
overlay.style.display = "none";
|
|
544
|
+
}
|
|
541
545
|
const container = document.createElement("div");
|
|
542
546
|
container.setAttribute("data-blink-container", "");
|
|
543
547
|
const iframe = document.createElement("iframe");
|
|
@@ -563,8 +567,8 @@ function createIframe(url, containerElement) {
|
|
|
563
567
|
};
|
|
564
568
|
attachBridge();
|
|
565
569
|
iframe.addEventListener("load", attachBridge);
|
|
566
|
-
|
|
567
|
-
|
|
570
|
+
let savedOverflow = "";
|
|
571
|
+
let scrollLocked = false;
|
|
568
572
|
const onBackdropClick = (event) => {
|
|
569
573
|
if (event.target === overlay) triggerClose();
|
|
570
574
|
};
|
|
@@ -574,15 +578,29 @@ function createIframe(url, containerElement) {
|
|
|
574
578
|
const onTouchMove = (event) => {
|
|
575
579
|
if (event.target === overlay) event.preventDefault();
|
|
576
580
|
};
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
581
|
+
function lockScroll() {
|
|
582
|
+
if (scrollLocked) return;
|
|
583
|
+
scrollLocked = true;
|
|
584
|
+
savedOverflow = document.body.style.overflow;
|
|
585
|
+
document.body.style.overflow = "hidden";
|
|
586
|
+
}
|
|
587
|
+
function attachDismissalListeners() {
|
|
588
|
+
overlay.addEventListener("click", onBackdropClick);
|
|
589
|
+
overlay.addEventListener("touchmove", onTouchMove, { passive: false });
|
|
590
|
+
document.addEventListener("keydown", onKeyDown);
|
|
591
|
+
}
|
|
592
|
+
if (!hidden) {
|
|
593
|
+
lockScroll();
|
|
594
|
+
attachDismissalListeners();
|
|
595
|
+
}
|
|
580
596
|
function removeListeners() {
|
|
581
597
|
overlay.removeEventListener("click", onBackdropClick);
|
|
582
598
|
overlay.removeEventListener("touchmove", onTouchMove);
|
|
583
599
|
document.removeEventListener("keydown", onKeyDown);
|
|
584
600
|
}
|
|
585
601
|
function unlockScroll() {
|
|
602
|
+
if (!scrollLocked) return;
|
|
603
|
+
scrollLocked = false;
|
|
586
604
|
document.body.style.overflow = savedOverflow;
|
|
587
605
|
}
|
|
588
606
|
function triggerClose() {
|
|
@@ -620,6 +638,21 @@ function createIframe(url, containerElement) {
|
|
|
620
638
|
isClosed() {
|
|
621
639
|
return closed;
|
|
622
640
|
},
|
|
641
|
+
isHidden() {
|
|
642
|
+
return hidden;
|
|
643
|
+
},
|
|
644
|
+
reveal() {
|
|
645
|
+
if (closed || !hidden) return;
|
|
646
|
+
hidden = false;
|
|
647
|
+
if (shouldUseMobileSheetLayout()) {
|
|
648
|
+
overlay.setAttribute("data-blink-mobile-sheet", "");
|
|
649
|
+
} else {
|
|
650
|
+
overlay.removeAttribute("data-blink-mobile-sheet");
|
|
651
|
+
}
|
|
652
|
+
overlay.style.display = "";
|
|
653
|
+
lockScroll();
|
|
654
|
+
attachDismissalListeners();
|
|
655
|
+
},
|
|
623
656
|
onClose(callback) {
|
|
624
657
|
closeCallback = callback;
|
|
625
658
|
},
|
|
@@ -791,6 +824,13 @@ function buildSignerRequest(request, webviewBaseUrl) {
|
|
|
791
824
|
|
|
792
825
|
// src/checkout.ts
|
|
793
826
|
var DEFAULT_WEBVIEW_BASE_URL = "https://pay.blink.cash";
|
|
827
|
+
var SANDBOX_WEBVIEW_BASE_URL = "https://pay-sandbox.blink.cash";
|
|
828
|
+
var IFRAME_READY_TIMEOUT_MS = 2e3;
|
|
829
|
+
var WARM_IFRAME_READY_TIMEOUT_MS = 6e4;
|
|
830
|
+
function resolveWebviewBaseUrl(config) {
|
|
831
|
+
if (config.webviewBaseUrl) return config.webviewBaseUrl;
|
|
832
|
+
return config.environment === "sandbox" ? SANDBOX_WEBVIEW_BASE_URL : DEFAULT_WEBVIEW_BASE_URL;
|
|
833
|
+
}
|
|
794
834
|
var Deposit = class {
|
|
795
835
|
config;
|
|
796
836
|
iframe = null;
|
|
@@ -803,6 +843,9 @@ var Deposit = class {
|
|
|
803
843
|
_error = null;
|
|
804
844
|
flowTimer = null;
|
|
805
845
|
lastSignerResponse = null;
|
|
846
|
+
warmIframe = null;
|
|
847
|
+
warmIframeReady = null;
|
|
848
|
+
warmIframeReadyCancel = null;
|
|
806
849
|
listeners = {
|
|
807
850
|
complete: /* @__PURE__ */ new Set(),
|
|
808
851
|
error: /* @__PURE__ */ new Set(),
|
|
@@ -833,6 +876,93 @@ var Deposit = class {
|
|
|
833
876
|
this.log("Deposit instance created", {
|
|
834
877
|
signer: typeof config.signer === "string" ? config.signer : "<function>"
|
|
835
878
|
});
|
|
879
|
+
if (config.preload !== false) {
|
|
880
|
+
this.schedulePreload();
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Warm up the hosted payment flow in a hidden iframe so `requestDeposit`
|
|
885
|
+
* opens an already-loaded page (JS bundle, auth session restore, and —
|
|
886
|
+
* when {@link DepositConfig.merchantId} is set — merchant config prefetch
|
|
887
|
+
* all happen in the background).
|
|
888
|
+
*
|
|
889
|
+
* Runs automatically after construction unless `preload: false`; call it
|
|
890
|
+
* manually to control the timing (e.g. on deposit-button hover). No-op
|
|
891
|
+
* when a warm iframe already exists or a deposit flow is active.
|
|
892
|
+
*/
|
|
893
|
+
preload() {
|
|
894
|
+
if (this.destroyed || this.isActive) return;
|
|
895
|
+
if (this.warmIframe && !this.warmIframe.isClosed()) return;
|
|
896
|
+
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
897
|
+
const webviewBaseUrl = resolveWebviewBaseUrl(this.config);
|
|
898
|
+
this.hostedOrigin = this.config.hostedFlowOrigin ?? new URL(webviewBaseUrl).origin;
|
|
899
|
+
const preloadUrl = this.buildPreloadUrl(webviewBaseUrl);
|
|
900
|
+
const iframe = createIframe(preloadUrl, this.config.containerElement, { hidden: true });
|
|
901
|
+
const ready = this.waitForIframeReady(iframe, WARM_IFRAME_READY_TIMEOUT_MS);
|
|
902
|
+
this.warmIframe = iframe;
|
|
903
|
+
this.warmIframeReady = ready.promise;
|
|
904
|
+
this.warmIframeReadyCancel = ready.cancel;
|
|
905
|
+
this.log("Warm-up iframe created", { url: preloadUrl });
|
|
906
|
+
}
|
|
907
|
+
// Defer the automatic warm-up until the host page has finished its own
|
|
908
|
+
// load and the main thread is idle — constructing a Deposit instance must
|
|
909
|
+
// never slow the merchant page down.
|
|
910
|
+
schedulePreload() {
|
|
911
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
912
|
+
const start = () => {
|
|
913
|
+
if (!this.destroyed && !this.isActive) this.preload();
|
|
914
|
+
};
|
|
915
|
+
const whenIdle = () => {
|
|
916
|
+
const w = window;
|
|
917
|
+
if (typeof w.requestIdleCallback === "function") {
|
|
918
|
+
w.requestIdleCallback(start, { timeout: 3e3 });
|
|
919
|
+
} else {
|
|
920
|
+
setTimeout(start, 250);
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
if (document.readyState === "complete") {
|
|
924
|
+
whenIdle();
|
|
925
|
+
} else {
|
|
926
|
+
window.addEventListener("load", whenIdle, { once: true });
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
buildPreloadUrl(webviewBaseUrl) {
|
|
930
|
+
const preloadUrl = new URL(webviewBaseUrl);
|
|
931
|
+
preloadUrl.searchParams.set("preload", "true");
|
|
932
|
+
if (this.config.merchantId) {
|
|
933
|
+
preloadUrl.searchParams.set("merchantId", this.config.merchantId);
|
|
934
|
+
}
|
|
935
|
+
this.applyFullWidgetParam(preloadUrl);
|
|
936
|
+
return preloadUrl.toString();
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* Detach the warm iframe for use by a starting flow. Returns null (and
|
|
940
|
+
* cleans up) when there is none or it was closed in the meantime.
|
|
941
|
+
*/
|
|
942
|
+
takeWarmIframe() {
|
|
943
|
+
const iframe = this.warmIframe;
|
|
944
|
+
const ready = this.warmIframeReady;
|
|
945
|
+
const cancelReady = this.warmIframeReadyCancel ?? (() => {
|
|
946
|
+
});
|
|
947
|
+
this.warmIframe = null;
|
|
948
|
+
this.warmIframeReady = null;
|
|
949
|
+
this.warmIframeReadyCancel = null;
|
|
950
|
+
if (!iframe || !ready) return null;
|
|
951
|
+
if (iframe.isClosed()) {
|
|
952
|
+
cancelReady();
|
|
953
|
+
iframe.destroy();
|
|
954
|
+
return null;
|
|
955
|
+
}
|
|
956
|
+
return { iframe, ready, cancelReady };
|
|
957
|
+
}
|
|
958
|
+
discardWarmIframe() {
|
|
959
|
+
this.warmIframeReadyCancel?.();
|
|
960
|
+
this.warmIframeReadyCancel = null;
|
|
961
|
+
this.warmIframeReady = null;
|
|
962
|
+
if (this.warmIframe) {
|
|
963
|
+
this.warmIframe.destroy();
|
|
964
|
+
this.warmIframe = null;
|
|
965
|
+
}
|
|
836
966
|
}
|
|
837
967
|
/**
|
|
838
968
|
* Open the hosted payment flow for the given deposit.
|
|
@@ -920,9 +1050,10 @@ var Deposit = class {
|
|
|
920
1050
|
/** Tear down the instance and release all resources. */
|
|
921
1051
|
destroy() {
|
|
922
1052
|
this.log("destroy() called");
|
|
1053
|
+
this.destroyed = true;
|
|
923
1054
|
this.cleanup();
|
|
1055
|
+
this.discardWarmIframe();
|
|
924
1056
|
this.setStatus("idle");
|
|
925
|
-
this.destroyed = true;
|
|
926
1057
|
for (const set of Object.values(this.listeners)) {
|
|
927
1058
|
set.clear();
|
|
928
1059
|
}
|
|
@@ -936,6 +1067,17 @@ var Deposit = class {
|
|
|
936
1067
|
console.debug(`[BlinkDeposit] ${message}`);
|
|
937
1068
|
}
|
|
938
1069
|
}
|
|
1070
|
+
/**
|
|
1071
|
+
* Appends `enableFullWidget=false` to the hosted-flow URL when the merchant
|
|
1072
|
+
* integration disables the full widget. Absence of the param means enabled
|
|
1073
|
+
* (the default) — the hosted flow ANDs this with the merchant's backend
|
|
1074
|
+
* config, so the full widget renders only when both allow it.
|
|
1075
|
+
*/
|
|
1076
|
+
applyFullWidgetParam(url) {
|
|
1077
|
+
if (this.config.enableFullWidget === false) {
|
|
1078
|
+
url.searchParams.set("enableFullWidget", "false");
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
939
1081
|
setStatus(status) {
|
|
940
1082
|
if (this._status === status) return;
|
|
941
1083
|
this.log(`Status: ${this._status} \u2192 ${status}`);
|
|
@@ -944,15 +1086,35 @@ var Deposit = class {
|
|
|
944
1086
|
}
|
|
945
1087
|
async runSignerFlow(request, requestId, onComplete, onError) {
|
|
946
1088
|
try {
|
|
947
|
-
const webviewBaseUrl = this.config
|
|
1089
|
+
const webviewBaseUrl = resolveWebviewBaseUrl(this.config);
|
|
948
1090
|
this.hostedOrigin = this.config.hostedFlowOrigin ?? new URL(webviewBaseUrl).origin;
|
|
949
1091
|
this.log("Calling signer", {
|
|
950
1092
|
signer: typeof this.config.signer === "string" ? this.config.signer : "<function>"
|
|
951
1093
|
});
|
|
952
1094
|
const signerRequest = buildSignerRequest(request, webviewBaseUrl);
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
const
|
|
1095
|
+
let preloadIframe;
|
|
1096
|
+
let iframeReadyPromise;
|
|
1097
|
+
const warm = this.takeWarmIframe();
|
|
1098
|
+
if (warm) {
|
|
1099
|
+
warm.iframe.reveal();
|
|
1100
|
+
preloadIframe = warm.iframe;
|
|
1101
|
+
iframeReadyPromise = Promise.race([
|
|
1102
|
+
warm.ready,
|
|
1103
|
+
new Promise(
|
|
1104
|
+
(resolve) => setTimeout(() => resolve(false), IFRAME_READY_TIMEOUT_MS)
|
|
1105
|
+
)
|
|
1106
|
+
]).then((ready) => {
|
|
1107
|
+
warm.cancelReady();
|
|
1108
|
+
return ready;
|
|
1109
|
+
});
|
|
1110
|
+
this.log("Reusing warm preload iframe");
|
|
1111
|
+
} else {
|
|
1112
|
+
preloadIframe = createIframe(
|
|
1113
|
+
this.buildPreloadUrl(webviewBaseUrl),
|
|
1114
|
+
this.config.containerElement
|
|
1115
|
+
);
|
|
1116
|
+
iframeReadyPromise = this.waitForIframeReady(preloadIframe).promise;
|
|
1117
|
+
}
|
|
956
1118
|
this.iframe = preloadIframe;
|
|
957
1119
|
preloadIframe.onClose(() => {
|
|
958
1120
|
onError(
|
|
@@ -969,7 +1131,6 @@ var Deposit = class {
|
|
|
969
1131
|
signerRequest,
|
|
970
1132
|
this.config.signerTimeoutMs
|
|
971
1133
|
);
|
|
972
|
-
const iframeReadyPromise = this.waitForIframeReady(preloadIframe);
|
|
973
1134
|
const [signerResponse, iframeReady] = await Promise.all([
|
|
974
1135
|
signerPromise,
|
|
975
1136
|
iframeReadyPromise
|
|
@@ -1001,6 +1162,7 @@ var Deposit = class {
|
|
|
1001
1162
|
hostedUrl.searchParams.set("merchantId", signerResponse.merchantId);
|
|
1002
1163
|
hostedUrl.searchParams.set("payload", signerResponse.payload);
|
|
1003
1164
|
hostedUrl.searchParams.set("signature", signerResponse.signature);
|
|
1165
|
+
this.applyFullWidgetParam(hostedUrl);
|
|
1004
1166
|
const targetUrl = hostedUrl.toString();
|
|
1005
1167
|
const iframeHandle = createIframe(targetUrl, this.config.containerElement);
|
|
1006
1168
|
this.iframe = iframeHandle;
|
|
@@ -1033,24 +1195,38 @@ var Deposit = class {
|
|
|
1033
1195
|
}
|
|
1034
1196
|
}
|
|
1035
1197
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1198
|
+
/**
|
|
1199
|
+
* Resolves true when the iframe posts `blink:iframe-ready`, false on
|
|
1200
|
+
* timeout. `cancel()` settles the promise as false immediately and releases
|
|
1201
|
+
* the listener + timer — used to reap the generous warm-up wait once it no
|
|
1202
|
+
* longer matters (warm iframe consumed or discarded).
|
|
1203
|
+
*/
|
|
1204
|
+
waitForIframeReady(iframeHandle, timeoutMs = IFRAME_READY_TIMEOUT_MS) {
|
|
1205
|
+
let finish = () => {
|
|
1206
|
+
};
|
|
1207
|
+
const promise = new Promise((resolve) => {
|
|
1038
1208
|
const handler = (event) => {
|
|
1039
1209
|
if (event.origin !== this.hostedOrigin) return;
|
|
1040
1210
|
if (event.source !== iframeHandle.contentWindow) return;
|
|
1041
1211
|
if (parseIframeReady(event.data)) {
|
|
1042
|
-
|
|
1043
|
-
clearTimeout(timeout);
|
|
1044
|
-
resolve(true);
|
|
1212
|
+
finish(true);
|
|
1045
1213
|
}
|
|
1046
1214
|
};
|
|
1047
1215
|
window.addEventListener("message", handler);
|
|
1048
1216
|
const timeout = setTimeout(() => {
|
|
1049
|
-
window.removeEventListener("message", handler);
|
|
1050
1217
|
this.log("Iframe ready timeout \u2014 falling back to URL params");
|
|
1051
|
-
|
|
1052
|
-
},
|
|
1218
|
+
finish(false);
|
|
1219
|
+
}, timeoutMs);
|
|
1220
|
+
let settled = false;
|
|
1221
|
+
finish = (ready) => {
|
|
1222
|
+
if (settled) return;
|
|
1223
|
+
settled = true;
|
|
1224
|
+
window.removeEventListener("message", handler);
|
|
1225
|
+
clearTimeout(timeout);
|
|
1226
|
+
resolve(ready);
|
|
1227
|
+
};
|
|
1053
1228
|
});
|
|
1229
|
+
return { promise, cancel: () => finish(false) };
|
|
1054
1230
|
}
|
|
1055
1231
|
startMessageListener(iframeHandle, onComplete) {
|
|
1056
1232
|
const handler = (event) => {
|
|
@@ -1110,6 +1286,9 @@ var Deposit = class {
|
|
|
1110
1286
|
}
|
|
1111
1287
|
this.hostedOrigin = null;
|
|
1112
1288
|
this.lastSignerResponse = null;
|
|
1289
|
+
if (!this.destroyed && this.config.preload !== false) {
|
|
1290
|
+
this.schedulePreload();
|
|
1291
|
+
}
|
|
1113
1292
|
}
|
|
1114
1293
|
emit(event, ...args) {
|
|
1115
1294
|
for (const handler of this.listeners[event]) {
|
|
@@ -1120,6 +1299,119 @@ var Deposit = class {
|
|
|
1120
1299
|
}
|
|
1121
1300
|
}
|
|
1122
1301
|
};
|
|
1302
|
+
function svgToDataUri(svg) {
|
|
1303
|
+
return `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
|
1304
|
+
}
|
|
1305
|
+
var USDC_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2000 2000">
|
|
1306
|
+
<path d="M1000 2000c554.17 0 1000-445.83 1000-1000S1554.17 0 1000 0 0 445.83 0 1000s445.83 1000 1000 1000z" fill="#2775ca"/>
|
|
1307
|
+
<path d="M1275 1158.33c0-145.83-87.5-195.83-262.5-216.66-125-16.67-150-50-150-108.34s41.67-95.83 125-95.83c75 0 116.67 25 137.5 87.5 4.17 12.5 16.67 20.83 29.17 20.83h66.66c16.67 0 29.17-12.5 29.17-29.16v-4.17c-16.67-91.67-91.67-162.5-187.5-170.83v-100c0-16.67-12.5-29.17-33.33-33.34h-62.5c-16.67 0-29.17 12.5-33.34 33.34v95.83c-125 16.67-204.16 100-204.16 204.17 0 137.5 83.33 191.66 258.33 212.5 116.67 20.83 154.17 45.83 154.17 112.5s-58.34 112.5-137.5 112.5c-108.34 0-145.84-45.84-158.34-108.34-4.16-16.66-16.66-25-29.16-25h-70.84c-16.66 0-29.16 12.5-29.16 29.17v4.17c16.66 104.16 83.33 179.16 220.83 200v100c0 16.66 12.5 29.16 33.33 33.33h62.5c16.67 0 29.17-12.5 33.34-33.33v-100c125-20.84 208.33-108.34 208.33-220.84z" fill="#fff"/>
|
|
1308
|
+
<path d="M787.5 1595.83c-325-116.66-491.67-479.16-370.83-800 62.5-175 200-308.33 370.83-370.83 16.67-8.33 25-20.83 25-41.67V325c0-16.67-8.33-29.17-25-33.33-4.17 0-12.5 0-16.67 4.16-395.83 125-612.5 545.84-487.5 941.67 75 233.33 254.17 412.5 487.5 487.5 16.67 8.33 33.34 0 37.5-16.67 4.17-4.16 4.17-8.33 4.17-16.66v-58.34c0-12.5-12.5-29.16-25-37.5zM1229.17 295.83c-16.67-8.33-33.34 0-37.5 16.67-4.17 4.17-4.17 8.33-4.17 16.67v58.33c0 16.67 12.5 33.33 25 41.67 325 116.66 491.67 479.16 370.83 800-62.5 175-200 308.33-370.83 370.83-16.67 8.33-25 20.83-25 41.67V1700c0 16.67 8.33 29.17 25 33.33 4.17 0 12.5 0 16.67-4.16 395.83-125 612.5-545.84 487.5-941.67-75-237.5-258.34-416.67-487.5-491.67z" fill="#fff"/>
|
|
1309
|
+
</svg>`;
|
|
1310
|
+
var TETHER_SVG = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800">
|
|
1311
|
+
<circle fill="#009393" cx="400" cy="400" r="400"/>
|
|
1312
|
+
<path fill="#fff" fill-rule="evenodd" d="M400.49,428.59c68.79,0,126.28-11.63,140.33-27.17-11.93-13.18-55.08-23.56-109.88-26.4v32.83c-9.81.51-20.01.76-30.46.76s-20.65-.25-30.48-.76v-32.83c-54.78,2.84-97.95,13.22-109.88,26.4,14.07,15.54,71.57,27.17,140.36,27.17ZM522.71,274.06v45.21h-91.77v31.35c64.46,3.35,112.83,17.13,113.19,33.62v34.38c-.36,16.49-48.73,30.24-113.19,33.6v76.94h-60.93v-76.94c-64.46-3.35-112.81-17.11-113.17-33.6v-34.38c.36-16.49,48.71-30.27,113.17-33.62v-31.35h-91.77v-45.21h244.48ZM242.15,202.11h322.16c7.7,0,14.79,4.05,18.63,10.63l93.85,161.16c4.86,8.36,3.42,18.91-3.52,25.68l-258.34,252.18c-8.38,8.17-21.84,8.17-30.2,0L126.71,399.92c-7.09-6.94-8.43-17.79-3.2-26.19l100.33-161.49c3.91-6.28,10.85-10.12,18.32-10.12Z"/>
|
|
1313
|
+
</svg>`;
|
|
1314
|
+
var USDC_LOGO = svgToDataUri(USDC_SVG);
|
|
1315
|
+
var TETHER_LOGO = svgToDataUri(TETHER_SVG);
|
|
1316
|
+
function BlinkDepositButton({
|
|
1317
|
+
onClick,
|
|
1318
|
+
disabled,
|
|
1319
|
+
loading
|
|
1320
|
+
}) {
|
|
1321
|
+
const [hovered, setHovered] = react.useState(false);
|
|
1322
|
+
const [pressed, setPressed] = react.useState(false);
|
|
1323
|
+
const inactive = !!disabled || !!loading;
|
|
1324
|
+
return react.createElement(
|
|
1325
|
+
"button",
|
|
1326
|
+
{
|
|
1327
|
+
type: "button",
|
|
1328
|
+
onClick,
|
|
1329
|
+
disabled: inactive,
|
|
1330
|
+
onMouseEnter: () => setHovered(true),
|
|
1331
|
+
onMouseLeave: () => {
|
|
1332
|
+
setHovered(false);
|
|
1333
|
+
setPressed(false);
|
|
1334
|
+
},
|
|
1335
|
+
onMouseDown: () => setPressed(true),
|
|
1336
|
+
onMouseUp: () => setPressed(false),
|
|
1337
|
+
style: pillStyle({ hovered, pressed, inactive, loading: !!loading })
|
|
1338
|
+
},
|
|
1339
|
+
react.createElement(
|
|
1340
|
+
"span",
|
|
1341
|
+
{ style: labelStackStyle },
|
|
1342
|
+
react.createElement("span", { style: titleStyle }, "Deposit stablecoins"),
|
|
1343
|
+
react.createElement("span", { style: subtitleStyle }, "In a Blink")
|
|
1344
|
+
),
|
|
1345
|
+
react.createElement(
|
|
1346
|
+
"span",
|
|
1347
|
+
{ style: coinsStyle },
|
|
1348
|
+
// The left (USDC) coin paints over the right one, against DOM paint order.
|
|
1349
|
+
react.createElement("img", {
|
|
1350
|
+
src: USDC_LOGO,
|
|
1351
|
+
alt: "",
|
|
1352
|
+
"aria-hidden": "true",
|
|
1353
|
+
style: { ...coinStyle, marginRight: -8, position: "relative", zIndex: 1 }
|
|
1354
|
+
}),
|
|
1355
|
+
react.createElement("img", { src: TETHER_LOGO, alt: "", "aria-hidden": "true", style: coinStyle })
|
|
1356
|
+
)
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
var pillStyle = (state) => ({
|
|
1360
|
+
display: "flex",
|
|
1361
|
+
alignItems: "center",
|
|
1362
|
+
justifyContent: "space-between",
|
|
1363
|
+
gap: 8,
|
|
1364
|
+
width: "100%",
|
|
1365
|
+
height: 56,
|
|
1366
|
+
padding: "12px 15px 12px 22px",
|
|
1367
|
+
backgroundColor: "#000000",
|
|
1368
|
+
// A faint white film on hover rather than `filter: brightness()` — a
|
|
1369
|
+
// brightness multiply leaves pure black unchanged.
|
|
1370
|
+
backgroundImage: !state.inactive && state.hovered ? "linear-gradient(rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.12))" : void 0,
|
|
1371
|
+
color: "#fafafa",
|
|
1372
|
+
border: "none",
|
|
1373
|
+
borderRadius: 36,
|
|
1374
|
+
cursor: state.inactive ? state.loading ? "progress" : "not-allowed" : "pointer",
|
|
1375
|
+
opacity: state.inactive ? 0.72 : 1,
|
|
1376
|
+
boxSizing: "border-box",
|
|
1377
|
+
// Explicit stack so the button is self-sufficient on any host page.
|
|
1378
|
+
fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
|
|
1379
|
+
textAlign: "left",
|
|
1380
|
+
transform: !state.inactive && state.pressed ? "scale(0.98)" : void 0,
|
|
1381
|
+
transition: "background-color 0.15s ease, transform 0.15s ease, opacity 0.15s ease"
|
|
1382
|
+
});
|
|
1383
|
+
var labelStackStyle = {
|
|
1384
|
+
display: "flex",
|
|
1385
|
+
flexDirection: "column",
|
|
1386
|
+
minWidth: 0
|
|
1387
|
+
};
|
|
1388
|
+
var titleStyle = {
|
|
1389
|
+
fontSize: 16,
|
|
1390
|
+
fontWeight: 700,
|
|
1391
|
+
lineHeight: "normal",
|
|
1392
|
+
whiteSpace: "nowrap"
|
|
1393
|
+
};
|
|
1394
|
+
var subtitleStyle = {
|
|
1395
|
+
fontSize: 16,
|
|
1396
|
+
fontWeight: 400,
|
|
1397
|
+
fontStyle: "italic",
|
|
1398
|
+
lineHeight: "normal",
|
|
1399
|
+
whiteSpace: "nowrap"
|
|
1400
|
+
};
|
|
1401
|
+
var coinsStyle = {
|
|
1402
|
+
display: "inline-flex",
|
|
1403
|
+
alignItems: "center",
|
|
1404
|
+
flexShrink: 0,
|
|
1405
|
+
// Scope the front coin's z-index so it can't escape over host page layers.
|
|
1406
|
+
isolation: "isolate"
|
|
1407
|
+
};
|
|
1408
|
+
var coinStyle = {
|
|
1409
|
+
width: 29,
|
|
1410
|
+
height: 29,
|
|
1411
|
+
borderRadius: "50%",
|
|
1412
|
+
objectFit: "cover",
|
|
1413
|
+
display: "block"
|
|
1414
|
+
};
|
|
1123
1415
|
|
|
1124
1416
|
// src/react.ts
|
|
1125
1417
|
function useBlinkDeposit(config) {
|
|
@@ -1163,6 +1455,7 @@ function useBlinkDeposit(config) {
|
|
|
1163
1455
|
var useBlinkCheckout = useBlinkDeposit;
|
|
1164
1456
|
var useSwypeCheckout = useBlinkDeposit;
|
|
1165
1457
|
|
|
1458
|
+
exports.BlinkDepositButton = BlinkDepositButton;
|
|
1166
1459
|
exports.DepositError = DepositError;
|
|
1167
1460
|
exports.getDisplayMessage = getDisplayMessage;
|
|
1168
1461
|
exports.useBlinkCheckout = useBlinkCheckout;
|