@swype-org/deposit 0.3.15 → 0.3.19
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 +10 -0
- package/dist/{chunk-MA7CVDFD.js → chunk-VMXCXXVN.js} +209 -24
- package/dist/chunk-VMXCXXVN.js.map +1 -0
- package/dist/index.cjs +207 -21
- 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 +320 -21
- 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 +5 -2
- package/dist/chunk-MA7CVDFD.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
|
@@ -251,7 +251,13 @@ var ALLOWED_RPC_METHODS = /* @__PURE__ */ new Set([
|
|
|
251
251
|
"wallet_addEthereumChain",
|
|
252
252
|
"wallet_switchEthereumChain",
|
|
253
253
|
"wallet_sendCalls",
|
|
254
|
-
"wallet_watchAsset"
|
|
254
|
+
"wallet_watchAsset",
|
|
255
|
+
// EIP-2255: lets the SDK revoke the dApp's `eth_accounts` grant before
|
|
256
|
+
// re-prompting on "+ Add wallet" / back-from-setup, so MetaMask shows the
|
|
257
|
+
// account picker instead of silently reusing the previously-permitted
|
|
258
|
+
// account. Wallets that don't implement it return method-not-supported,
|
|
259
|
+
// which the SDK swallows.
|
|
260
|
+
"wallet_revokePermissions"
|
|
255
261
|
]);
|
|
256
262
|
var FORWARDED_PROVIDER_EVENTS = [
|
|
257
263
|
"accountsChanged",
|
|
@@ -523,15 +529,19 @@ var STYLES = `
|
|
|
523
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}
|
|
524
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}}
|
|
525
531
|
`;
|
|
526
|
-
function createIframe(url, containerElement) {
|
|
532
|
+
function createIframe(url, containerElement, options) {
|
|
527
533
|
ensureStyles();
|
|
528
534
|
let closed = false;
|
|
535
|
+
let hidden = options?.hidden === true;
|
|
529
536
|
let closeCallback = null;
|
|
530
537
|
const overlay = document.createElement("div");
|
|
531
538
|
overlay.setAttribute("data-blink-overlay", "");
|
|
532
539
|
if (shouldUseMobileSheetLayout()) {
|
|
533
540
|
overlay.setAttribute("data-blink-mobile-sheet", "");
|
|
534
541
|
}
|
|
542
|
+
if (hidden) {
|
|
543
|
+
overlay.style.display = "none";
|
|
544
|
+
}
|
|
535
545
|
const container = document.createElement("div");
|
|
536
546
|
container.setAttribute("data-blink-container", "");
|
|
537
547
|
const iframe = document.createElement("iframe");
|
|
@@ -557,8 +567,8 @@ function createIframe(url, containerElement) {
|
|
|
557
567
|
};
|
|
558
568
|
attachBridge();
|
|
559
569
|
iframe.addEventListener("load", attachBridge);
|
|
560
|
-
|
|
561
|
-
|
|
570
|
+
let savedOverflow = "";
|
|
571
|
+
let scrollLocked = false;
|
|
562
572
|
const onBackdropClick = (event) => {
|
|
563
573
|
if (event.target === overlay) triggerClose();
|
|
564
574
|
};
|
|
@@ -568,15 +578,29 @@ function createIframe(url, containerElement) {
|
|
|
568
578
|
const onTouchMove = (event) => {
|
|
569
579
|
if (event.target === overlay) event.preventDefault();
|
|
570
580
|
};
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
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
|
+
}
|
|
574
596
|
function removeListeners() {
|
|
575
597
|
overlay.removeEventListener("click", onBackdropClick);
|
|
576
598
|
overlay.removeEventListener("touchmove", onTouchMove);
|
|
577
599
|
document.removeEventListener("keydown", onKeyDown);
|
|
578
600
|
}
|
|
579
601
|
function unlockScroll() {
|
|
602
|
+
if (!scrollLocked) return;
|
|
603
|
+
scrollLocked = false;
|
|
580
604
|
document.body.style.overflow = savedOverflow;
|
|
581
605
|
}
|
|
582
606
|
function triggerClose() {
|
|
@@ -614,6 +638,21 @@ function createIframe(url, containerElement) {
|
|
|
614
638
|
isClosed() {
|
|
615
639
|
return closed;
|
|
616
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
|
+
},
|
|
617
656
|
onClose(callback) {
|
|
618
657
|
closeCallback = callback;
|
|
619
658
|
},
|
|
@@ -785,6 +824,13 @@ function buildSignerRequest(request, webviewBaseUrl) {
|
|
|
785
824
|
|
|
786
825
|
// src/checkout.ts
|
|
787
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
|
+
}
|
|
788
834
|
var Deposit = class {
|
|
789
835
|
config;
|
|
790
836
|
iframe = null;
|
|
@@ -797,6 +843,9 @@ var Deposit = class {
|
|
|
797
843
|
_error = null;
|
|
798
844
|
flowTimer = null;
|
|
799
845
|
lastSignerResponse = null;
|
|
846
|
+
warmIframe = null;
|
|
847
|
+
warmIframeReady = null;
|
|
848
|
+
warmIframeReadyCancel = null;
|
|
800
849
|
listeners = {
|
|
801
850
|
complete: /* @__PURE__ */ new Set(),
|
|
802
851
|
error: /* @__PURE__ */ new Set(),
|
|
@@ -827,6 +876,93 @@ var Deposit = class {
|
|
|
827
876
|
this.log("Deposit instance created", {
|
|
828
877
|
signer: typeof config.signer === "string" ? config.signer : "<function>"
|
|
829
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
|
+
}
|
|
830
966
|
}
|
|
831
967
|
/**
|
|
832
968
|
* Open the hosted payment flow for the given deposit.
|
|
@@ -914,9 +1050,10 @@ var Deposit = class {
|
|
|
914
1050
|
/** Tear down the instance and release all resources. */
|
|
915
1051
|
destroy() {
|
|
916
1052
|
this.log("destroy() called");
|
|
1053
|
+
this.destroyed = true;
|
|
917
1054
|
this.cleanup();
|
|
1055
|
+
this.discardWarmIframe();
|
|
918
1056
|
this.setStatus("idle");
|
|
919
|
-
this.destroyed = true;
|
|
920
1057
|
for (const set of Object.values(this.listeners)) {
|
|
921
1058
|
set.clear();
|
|
922
1059
|
}
|
|
@@ -930,6 +1067,17 @@ var Deposit = class {
|
|
|
930
1067
|
console.debug(`[BlinkDeposit] ${message}`);
|
|
931
1068
|
}
|
|
932
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
|
+
}
|
|
933
1081
|
setStatus(status) {
|
|
934
1082
|
if (this._status === status) return;
|
|
935
1083
|
this.log(`Status: ${this._status} \u2192 ${status}`);
|
|
@@ -938,15 +1086,35 @@ var Deposit = class {
|
|
|
938
1086
|
}
|
|
939
1087
|
async runSignerFlow(request, requestId, onComplete, onError) {
|
|
940
1088
|
try {
|
|
941
|
-
const webviewBaseUrl = this.config
|
|
1089
|
+
const webviewBaseUrl = resolveWebviewBaseUrl(this.config);
|
|
942
1090
|
this.hostedOrigin = this.config.hostedFlowOrigin ?? new URL(webviewBaseUrl).origin;
|
|
943
1091
|
this.log("Calling signer", {
|
|
944
1092
|
signer: typeof this.config.signer === "string" ? this.config.signer : "<function>"
|
|
945
1093
|
});
|
|
946
1094
|
const signerRequest = buildSignerRequest(request, webviewBaseUrl);
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
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
|
+
}
|
|
950
1118
|
this.iframe = preloadIframe;
|
|
951
1119
|
preloadIframe.onClose(() => {
|
|
952
1120
|
onError(
|
|
@@ -963,7 +1131,6 @@ var Deposit = class {
|
|
|
963
1131
|
signerRequest,
|
|
964
1132
|
this.config.signerTimeoutMs
|
|
965
1133
|
);
|
|
966
|
-
const iframeReadyPromise = this.waitForIframeReady(preloadIframe);
|
|
967
1134
|
const [signerResponse, iframeReady] = await Promise.all([
|
|
968
1135
|
signerPromise,
|
|
969
1136
|
iframeReadyPromise
|
|
@@ -995,6 +1162,7 @@ var Deposit = class {
|
|
|
995
1162
|
hostedUrl.searchParams.set("merchantId", signerResponse.merchantId);
|
|
996
1163
|
hostedUrl.searchParams.set("payload", signerResponse.payload);
|
|
997
1164
|
hostedUrl.searchParams.set("signature", signerResponse.signature);
|
|
1165
|
+
this.applyFullWidgetParam(hostedUrl);
|
|
998
1166
|
const targetUrl = hostedUrl.toString();
|
|
999
1167
|
const iframeHandle = createIframe(targetUrl, this.config.containerElement);
|
|
1000
1168
|
this.iframe = iframeHandle;
|
|
@@ -1027,24 +1195,38 @@ var Deposit = class {
|
|
|
1027
1195
|
}
|
|
1028
1196
|
}
|
|
1029
1197
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
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) => {
|
|
1032
1208
|
const handler = (event) => {
|
|
1033
1209
|
if (event.origin !== this.hostedOrigin) return;
|
|
1034
1210
|
if (event.source !== iframeHandle.contentWindow) return;
|
|
1035
1211
|
if (parseIframeReady(event.data)) {
|
|
1036
|
-
|
|
1037
|
-
clearTimeout(timeout);
|
|
1038
|
-
resolve(true);
|
|
1212
|
+
finish(true);
|
|
1039
1213
|
}
|
|
1040
1214
|
};
|
|
1041
1215
|
window.addEventListener("message", handler);
|
|
1042
1216
|
const timeout = setTimeout(() => {
|
|
1043
|
-
window.removeEventListener("message", handler);
|
|
1044
1217
|
this.log("Iframe ready timeout \u2014 falling back to URL params");
|
|
1045
|
-
|
|
1046
|
-
},
|
|
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
|
+
};
|
|
1047
1228
|
});
|
|
1229
|
+
return { promise, cancel: () => finish(false) };
|
|
1048
1230
|
}
|
|
1049
1231
|
startMessageListener(iframeHandle, onComplete) {
|
|
1050
1232
|
const handler = (event) => {
|
|
@@ -1104,6 +1286,9 @@ var Deposit = class {
|
|
|
1104
1286
|
}
|
|
1105
1287
|
this.hostedOrigin = null;
|
|
1106
1288
|
this.lastSignerResponse = null;
|
|
1289
|
+
if (!this.destroyed && this.config.preload !== false) {
|
|
1290
|
+
this.schedulePreload();
|
|
1291
|
+
}
|
|
1107
1292
|
}
|
|
1108
1293
|
emit(event, ...args) {
|
|
1109
1294
|
for (const handler of this.listeners[event]) {
|
|
@@ -1114,6 +1299,119 @@ var Deposit = class {
|
|
|
1114
1299
|
}
|
|
1115
1300
|
}
|
|
1116
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
|
+
};
|
|
1117
1415
|
|
|
1118
1416
|
// src/react.ts
|
|
1119
1417
|
function useBlinkDeposit(config) {
|
|
@@ -1157,6 +1455,7 @@ function useBlinkDeposit(config) {
|
|
|
1157
1455
|
var useBlinkCheckout = useBlinkDeposit;
|
|
1158
1456
|
var useSwypeCheckout = useBlinkDeposit;
|
|
1159
1457
|
|
|
1458
|
+
exports.BlinkDepositButton = BlinkDepositButton;
|
|
1160
1459
|
exports.DepositError = DepositError;
|
|
1161
1460
|
exports.getDisplayMessage = getDisplayMessage;
|
|
1162
1461
|
exports.useBlinkCheckout = useBlinkCheckout;
|