@swype-org/deposit 0.3.16 → 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-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 +5 -2
- package/dist/chunk-WD6DVQHT.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -526,15 +526,19 @@ var STYLES = `
|
|
|
526
526
|
[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}
|
|
527
527
|
@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}}
|
|
528
528
|
`;
|
|
529
|
-
function createIframe(url, containerElement) {
|
|
529
|
+
function createIframe(url, containerElement, options) {
|
|
530
530
|
ensureStyles();
|
|
531
531
|
let closed = false;
|
|
532
|
+
let hidden = options?.hidden === true;
|
|
532
533
|
let closeCallback = null;
|
|
533
534
|
const overlay = document.createElement("div");
|
|
534
535
|
overlay.setAttribute("data-blink-overlay", "");
|
|
535
536
|
if (shouldUseMobileSheetLayout()) {
|
|
536
537
|
overlay.setAttribute("data-blink-mobile-sheet", "");
|
|
537
538
|
}
|
|
539
|
+
if (hidden) {
|
|
540
|
+
overlay.style.display = "none";
|
|
541
|
+
}
|
|
538
542
|
const container = document.createElement("div");
|
|
539
543
|
container.setAttribute("data-blink-container", "");
|
|
540
544
|
const iframe = document.createElement("iframe");
|
|
@@ -560,8 +564,8 @@ function createIframe(url, containerElement) {
|
|
|
560
564
|
};
|
|
561
565
|
attachBridge();
|
|
562
566
|
iframe.addEventListener("load", attachBridge);
|
|
563
|
-
|
|
564
|
-
|
|
567
|
+
let savedOverflow = "";
|
|
568
|
+
let scrollLocked = false;
|
|
565
569
|
const onBackdropClick = (event) => {
|
|
566
570
|
if (event.target === overlay) triggerClose();
|
|
567
571
|
};
|
|
@@ -571,15 +575,29 @@ function createIframe(url, containerElement) {
|
|
|
571
575
|
const onTouchMove = (event) => {
|
|
572
576
|
if (event.target === overlay) event.preventDefault();
|
|
573
577
|
};
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
578
|
+
function lockScroll() {
|
|
579
|
+
if (scrollLocked) return;
|
|
580
|
+
scrollLocked = true;
|
|
581
|
+
savedOverflow = document.body.style.overflow;
|
|
582
|
+
document.body.style.overflow = "hidden";
|
|
583
|
+
}
|
|
584
|
+
function attachDismissalListeners() {
|
|
585
|
+
overlay.addEventListener("click", onBackdropClick);
|
|
586
|
+
overlay.addEventListener("touchmove", onTouchMove, { passive: false });
|
|
587
|
+
document.addEventListener("keydown", onKeyDown);
|
|
588
|
+
}
|
|
589
|
+
if (!hidden) {
|
|
590
|
+
lockScroll();
|
|
591
|
+
attachDismissalListeners();
|
|
592
|
+
}
|
|
577
593
|
function removeListeners() {
|
|
578
594
|
overlay.removeEventListener("click", onBackdropClick);
|
|
579
595
|
overlay.removeEventListener("touchmove", onTouchMove);
|
|
580
596
|
document.removeEventListener("keydown", onKeyDown);
|
|
581
597
|
}
|
|
582
598
|
function unlockScroll() {
|
|
599
|
+
if (!scrollLocked) return;
|
|
600
|
+
scrollLocked = false;
|
|
583
601
|
document.body.style.overflow = savedOverflow;
|
|
584
602
|
}
|
|
585
603
|
function triggerClose() {
|
|
@@ -617,6 +635,21 @@ function createIframe(url, containerElement) {
|
|
|
617
635
|
isClosed() {
|
|
618
636
|
return closed;
|
|
619
637
|
},
|
|
638
|
+
isHidden() {
|
|
639
|
+
return hidden;
|
|
640
|
+
},
|
|
641
|
+
reveal() {
|
|
642
|
+
if (closed || !hidden) return;
|
|
643
|
+
hidden = false;
|
|
644
|
+
if (shouldUseMobileSheetLayout()) {
|
|
645
|
+
overlay.setAttribute("data-blink-mobile-sheet", "");
|
|
646
|
+
} else {
|
|
647
|
+
overlay.removeAttribute("data-blink-mobile-sheet");
|
|
648
|
+
}
|
|
649
|
+
overlay.style.display = "";
|
|
650
|
+
lockScroll();
|
|
651
|
+
attachDismissalListeners();
|
|
652
|
+
},
|
|
620
653
|
onClose(callback) {
|
|
621
654
|
closeCallback = callback;
|
|
622
655
|
},
|
|
@@ -788,6 +821,13 @@ function buildSignerRequest(request, webviewBaseUrl) {
|
|
|
788
821
|
|
|
789
822
|
// src/checkout.ts
|
|
790
823
|
var DEFAULT_WEBVIEW_BASE_URL = "https://pay.blink.cash";
|
|
824
|
+
var SANDBOX_WEBVIEW_BASE_URL = "https://pay-sandbox.blink.cash";
|
|
825
|
+
var IFRAME_READY_TIMEOUT_MS = 2e3;
|
|
826
|
+
var WARM_IFRAME_READY_TIMEOUT_MS = 6e4;
|
|
827
|
+
function resolveWebviewBaseUrl(config) {
|
|
828
|
+
if (config.webviewBaseUrl) return config.webviewBaseUrl;
|
|
829
|
+
return config.environment === "sandbox" ? SANDBOX_WEBVIEW_BASE_URL : DEFAULT_WEBVIEW_BASE_URL;
|
|
830
|
+
}
|
|
791
831
|
var Deposit = class {
|
|
792
832
|
config;
|
|
793
833
|
iframe = null;
|
|
@@ -800,6 +840,9 @@ var Deposit = class {
|
|
|
800
840
|
_error = null;
|
|
801
841
|
flowTimer = null;
|
|
802
842
|
lastSignerResponse = null;
|
|
843
|
+
warmIframe = null;
|
|
844
|
+
warmIframeReady = null;
|
|
845
|
+
warmIframeReadyCancel = null;
|
|
803
846
|
listeners = {
|
|
804
847
|
complete: /* @__PURE__ */ new Set(),
|
|
805
848
|
error: /* @__PURE__ */ new Set(),
|
|
@@ -830,6 +873,93 @@ var Deposit = class {
|
|
|
830
873
|
this.log("Deposit instance created", {
|
|
831
874
|
signer: typeof config.signer === "string" ? config.signer : "<function>"
|
|
832
875
|
});
|
|
876
|
+
if (config.preload !== false) {
|
|
877
|
+
this.schedulePreload();
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Warm up the hosted payment flow in a hidden iframe so `requestDeposit`
|
|
882
|
+
* opens an already-loaded page (JS bundle, auth session restore, and —
|
|
883
|
+
* when {@link DepositConfig.merchantId} is set — merchant config prefetch
|
|
884
|
+
* all happen in the background).
|
|
885
|
+
*
|
|
886
|
+
* Runs automatically after construction unless `preload: false`; call it
|
|
887
|
+
* manually to control the timing (e.g. on deposit-button hover). No-op
|
|
888
|
+
* when a warm iframe already exists or a deposit flow is active.
|
|
889
|
+
*/
|
|
890
|
+
preload() {
|
|
891
|
+
if (this.destroyed || this.isActive) return;
|
|
892
|
+
if (this.warmIframe && !this.warmIframe.isClosed()) return;
|
|
893
|
+
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
894
|
+
const webviewBaseUrl = resolveWebviewBaseUrl(this.config);
|
|
895
|
+
this.hostedOrigin = this.config.hostedFlowOrigin ?? new URL(webviewBaseUrl).origin;
|
|
896
|
+
const preloadUrl = this.buildPreloadUrl(webviewBaseUrl);
|
|
897
|
+
const iframe = createIframe(preloadUrl, this.config.containerElement, { hidden: true });
|
|
898
|
+
const ready = this.waitForIframeReady(iframe, WARM_IFRAME_READY_TIMEOUT_MS);
|
|
899
|
+
this.warmIframe = iframe;
|
|
900
|
+
this.warmIframeReady = ready.promise;
|
|
901
|
+
this.warmIframeReadyCancel = ready.cancel;
|
|
902
|
+
this.log("Warm-up iframe created", { url: preloadUrl });
|
|
903
|
+
}
|
|
904
|
+
// Defer the automatic warm-up until the host page has finished its own
|
|
905
|
+
// load and the main thread is idle — constructing a Deposit instance must
|
|
906
|
+
// never slow the merchant page down.
|
|
907
|
+
schedulePreload() {
|
|
908
|
+
if (typeof window === "undefined" || typeof document === "undefined") return;
|
|
909
|
+
const start = () => {
|
|
910
|
+
if (!this.destroyed && !this.isActive) this.preload();
|
|
911
|
+
};
|
|
912
|
+
const whenIdle = () => {
|
|
913
|
+
const w = window;
|
|
914
|
+
if (typeof w.requestIdleCallback === "function") {
|
|
915
|
+
w.requestIdleCallback(start, { timeout: 3e3 });
|
|
916
|
+
} else {
|
|
917
|
+
setTimeout(start, 250);
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
if (document.readyState === "complete") {
|
|
921
|
+
whenIdle();
|
|
922
|
+
} else {
|
|
923
|
+
window.addEventListener("load", whenIdle, { once: true });
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
buildPreloadUrl(webviewBaseUrl) {
|
|
927
|
+
const preloadUrl = new URL(webviewBaseUrl);
|
|
928
|
+
preloadUrl.searchParams.set("preload", "true");
|
|
929
|
+
if (this.config.merchantId) {
|
|
930
|
+
preloadUrl.searchParams.set("merchantId", this.config.merchantId);
|
|
931
|
+
}
|
|
932
|
+
this.applyFullWidgetParam(preloadUrl);
|
|
933
|
+
return preloadUrl.toString();
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Detach the warm iframe for use by a starting flow. Returns null (and
|
|
937
|
+
* cleans up) when there is none or it was closed in the meantime.
|
|
938
|
+
*/
|
|
939
|
+
takeWarmIframe() {
|
|
940
|
+
const iframe = this.warmIframe;
|
|
941
|
+
const ready = this.warmIframeReady;
|
|
942
|
+
const cancelReady = this.warmIframeReadyCancel ?? (() => {
|
|
943
|
+
});
|
|
944
|
+
this.warmIframe = null;
|
|
945
|
+
this.warmIframeReady = null;
|
|
946
|
+
this.warmIframeReadyCancel = null;
|
|
947
|
+
if (!iframe || !ready) return null;
|
|
948
|
+
if (iframe.isClosed()) {
|
|
949
|
+
cancelReady();
|
|
950
|
+
iframe.destroy();
|
|
951
|
+
return null;
|
|
952
|
+
}
|
|
953
|
+
return { iframe, ready, cancelReady };
|
|
954
|
+
}
|
|
955
|
+
discardWarmIframe() {
|
|
956
|
+
this.warmIframeReadyCancel?.();
|
|
957
|
+
this.warmIframeReadyCancel = null;
|
|
958
|
+
this.warmIframeReady = null;
|
|
959
|
+
if (this.warmIframe) {
|
|
960
|
+
this.warmIframe.destroy();
|
|
961
|
+
this.warmIframe = null;
|
|
962
|
+
}
|
|
833
963
|
}
|
|
834
964
|
/**
|
|
835
965
|
* Open the hosted payment flow for the given deposit.
|
|
@@ -917,9 +1047,10 @@ var Deposit = class {
|
|
|
917
1047
|
/** Tear down the instance and release all resources. */
|
|
918
1048
|
destroy() {
|
|
919
1049
|
this.log("destroy() called");
|
|
1050
|
+
this.destroyed = true;
|
|
920
1051
|
this.cleanup();
|
|
1052
|
+
this.discardWarmIframe();
|
|
921
1053
|
this.setStatus("idle");
|
|
922
|
-
this.destroyed = true;
|
|
923
1054
|
for (const set of Object.values(this.listeners)) {
|
|
924
1055
|
set.clear();
|
|
925
1056
|
}
|
|
@@ -933,6 +1064,17 @@ var Deposit = class {
|
|
|
933
1064
|
console.debug(`[BlinkDeposit] ${message}`);
|
|
934
1065
|
}
|
|
935
1066
|
}
|
|
1067
|
+
/**
|
|
1068
|
+
* Appends `enableFullWidget=false` to the hosted-flow URL when the merchant
|
|
1069
|
+
* integration disables the full widget. Absence of the param means enabled
|
|
1070
|
+
* (the default) — the hosted flow ANDs this with the merchant's backend
|
|
1071
|
+
* config, so the full widget renders only when both allow it.
|
|
1072
|
+
*/
|
|
1073
|
+
applyFullWidgetParam(url) {
|
|
1074
|
+
if (this.config.enableFullWidget === false) {
|
|
1075
|
+
url.searchParams.set("enableFullWidget", "false");
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
936
1078
|
setStatus(status) {
|
|
937
1079
|
if (this._status === status) return;
|
|
938
1080
|
this.log(`Status: ${this._status} \u2192 ${status}`);
|
|
@@ -941,15 +1083,35 @@ var Deposit = class {
|
|
|
941
1083
|
}
|
|
942
1084
|
async runSignerFlow(request, requestId, onComplete, onError) {
|
|
943
1085
|
try {
|
|
944
|
-
const webviewBaseUrl = this.config
|
|
1086
|
+
const webviewBaseUrl = resolveWebviewBaseUrl(this.config);
|
|
945
1087
|
this.hostedOrigin = this.config.hostedFlowOrigin ?? new URL(webviewBaseUrl).origin;
|
|
946
1088
|
this.log("Calling signer", {
|
|
947
1089
|
signer: typeof this.config.signer === "string" ? this.config.signer : "<function>"
|
|
948
1090
|
});
|
|
949
1091
|
const signerRequest = buildSignerRequest(request, webviewBaseUrl);
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
const
|
|
1092
|
+
let preloadIframe;
|
|
1093
|
+
let iframeReadyPromise;
|
|
1094
|
+
const warm = this.takeWarmIframe();
|
|
1095
|
+
if (warm) {
|
|
1096
|
+
warm.iframe.reveal();
|
|
1097
|
+
preloadIframe = warm.iframe;
|
|
1098
|
+
iframeReadyPromise = Promise.race([
|
|
1099
|
+
warm.ready,
|
|
1100
|
+
new Promise(
|
|
1101
|
+
(resolve) => setTimeout(() => resolve(false), IFRAME_READY_TIMEOUT_MS)
|
|
1102
|
+
)
|
|
1103
|
+
]).then((ready) => {
|
|
1104
|
+
warm.cancelReady();
|
|
1105
|
+
return ready;
|
|
1106
|
+
});
|
|
1107
|
+
this.log("Reusing warm preload iframe");
|
|
1108
|
+
} else {
|
|
1109
|
+
preloadIframe = createIframe(
|
|
1110
|
+
this.buildPreloadUrl(webviewBaseUrl),
|
|
1111
|
+
this.config.containerElement
|
|
1112
|
+
);
|
|
1113
|
+
iframeReadyPromise = this.waitForIframeReady(preloadIframe).promise;
|
|
1114
|
+
}
|
|
953
1115
|
this.iframe = preloadIframe;
|
|
954
1116
|
preloadIframe.onClose(() => {
|
|
955
1117
|
onError(
|
|
@@ -966,7 +1128,6 @@ var Deposit = class {
|
|
|
966
1128
|
signerRequest,
|
|
967
1129
|
this.config.signerTimeoutMs
|
|
968
1130
|
);
|
|
969
|
-
const iframeReadyPromise = this.waitForIframeReady(preloadIframe);
|
|
970
1131
|
const [signerResponse, iframeReady] = await Promise.all([
|
|
971
1132
|
signerPromise,
|
|
972
1133
|
iframeReadyPromise
|
|
@@ -998,6 +1159,7 @@ var Deposit = class {
|
|
|
998
1159
|
hostedUrl.searchParams.set("merchantId", signerResponse.merchantId);
|
|
999
1160
|
hostedUrl.searchParams.set("payload", signerResponse.payload);
|
|
1000
1161
|
hostedUrl.searchParams.set("signature", signerResponse.signature);
|
|
1162
|
+
this.applyFullWidgetParam(hostedUrl);
|
|
1001
1163
|
const targetUrl = hostedUrl.toString();
|
|
1002
1164
|
const iframeHandle = createIframe(targetUrl, this.config.containerElement);
|
|
1003
1165
|
this.iframe = iframeHandle;
|
|
@@ -1030,24 +1192,38 @@ var Deposit = class {
|
|
|
1030
1192
|
}
|
|
1031
1193
|
}
|
|
1032
1194
|
}
|
|
1033
|
-
|
|
1034
|
-
|
|
1195
|
+
/**
|
|
1196
|
+
* Resolves true when the iframe posts `blink:iframe-ready`, false on
|
|
1197
|
+
* timeout. `cancel()` settles the promise as false immediately and releases
|
|
1198
|
+
* the listener + timer — used to reap the generous warm-up wait once it no
|
|
1199
|
+
* longer matters (warm iframe consumed or discarded).
|
|
1200
|
+
*/
|
|
1201
|
+
waitForIframeReady(iframeHandle, timeoutMs = IFRAME_READY_TIMEOUT_MS) {
|
|
1202
|
+
let finish = () => {
|
|
1203
|
+
};
|
|
1204
|
+
const promise = new Promise((resolve) => {
|
|
1035
1205
|
const handler = (event) => {
|
|
1036
1206
|
if (event.origin !== this.hostedOrigin) return;
|
|
1037
1207
|
if (event.source !== iframeHandle.contentWindow) return;
|
|
1038
1208
|
if (parseIframeReady(event.data)) {
|
|
1039
|
-
|
|
1040
|
-
clearTimeout(timeout);
|
|
1041
|
-
resolve(true);
|
|
1209
|
+
finish(true);
|
|
1042
1210
|
}
|
|
1043
1211
|
};
|
|
1044
1212
|
window.addEventListener("message", handler);
|
|
1045
1213
|
const timeout = setTimeout(() => {
|
|
1046
|
-
window.removeEventListener("message", handler);
|
|
1047
1214
|
this.log("Iframe ready timeout \u2014 falling back to URL params");
|
|
1048
|
-
|
|
1049
|
-
},
|
|
1215
|
+
finish(false);
|
|
1216
|
+
}, timeoutMs);
|
|
1217
|
+
let settled = false;
|
|
1218
|
+
finish = (ready) => {
|
|
1219
|
+
if (settled) return;
|
|
1220
|
+
settled = true;
|
|
1221
|
+
window.removeEventListener("message", handler);
|
|
1222
|
+
clearTimeout(timeout);
|
|
1223
|
+
resolve(ready);
|
|
1224
|
+
};
|
|
1050
1225
|
});
|
|
1226
|
+
return { promise, cancel: () => finish(false) };
|
|
1051
1227
|
}
|
|
1052
1228
|
startMessageListener(iframeHandle, onComplete) {
|
|
1053
1229
|
const handler = (event) => {
|
|
@@ -1107,6 +1283,9 @@ var Deposit = class {
|
|
|
1107
1283
|
}
|
|
1108
1284
|
this.hostedOrigin = null;
|
|
1109
1285
|
this.lastSignerResponse = null;
|
|
1286
|
+
if (!this.destroyed && this.config.preload !== false) {
|
|
1287
|
+
this.schedulePreload();
|
|
1288
|
+
}
|
|
1110
1289
|
}
|
|
1111
1290
|
emit(event, ...args) {
|
|
1112
1291
|
for (const handler of this.listeners[event]) {
|
|
@@ -1129,6 +1308,7 @@ exports.CheckoutError = CheckoutError;
|
|
|
1129
1308
|
exports.DEFAULT_WEBVIEW_BASE_URL = DEFAULT_WEBVIEW_BASE_URL;
|
|
1130
1309
|
exports.Deposit = Deposit;
|
|
1131
1310
|
exports.DepositError = DepositError;
|
|
1311
|
+
exports.SANDBOX_WEBVIEW_BASE_URL = SANDBOX_WEBVIEW_BASE_URL;
|
|
1132
1312
|
exports.VERSION = VERSION;
|
|
1133
1313
|
exports.attachRpcHost = attachRpcHost;
|
|
1134
1314
|
exports.createWalletDiscoverer = createWalletDiscoverer;
|