@swype-org/deposit 0.3.26 → 0.3.32
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 +171 -0
- package/dist/{chunk-S3SPMEXQ.js → chunk-MJSD7JWR.js} +534 -98
- package/dist/chunk-MJSD7JWR.js.map +1 -0
- package/dist/index.cjs +533 -97
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +142 -5
- package/dist/index.d.ts +142 -5
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +532 -96
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +2 -2
- package/dist/react.d.ts +2 -2
- package/dist/react.js +2 -2
- package/dist/{types-BjnQ2ux2.d.cts → types-QRkKxsoP.d.cts} +128 -1
- package/dist/{types-BjnQ2ux2.d.ts → types-QRkKxsoP.d.ts} +128 -1
- package/package.json +1 -1
- package/dist/chunk-S3SPMEXQ.js.map +0 -1
package/dist/react.cjs
CHANGED
|
@@ -109,21 +109,84 @@ function parseCapabilities(value) {
|
|
|
109
109
|
}
|
|
110
110
|
return value.filter((entry) => typeof entry === "string");
|
|
111
111
|
}
|
|
112
|
-
function buildViewportMessage(viewportLvh, safeAreaBottom) {
|
|
113
|
-
return {
|
|
112
|
+
function buildViewportMessage(viewportLvh, safeAreaBottom, embedMaxHeightPx) {
|
|
113
|
+
return {
|
|
114
|
+
type: "blink:viewport",
|
|
115
|
+
viewportLvh,
|
|
116
|
+
safeAreaBottom,
|
|
117
|
+
...embedMaxHeightPx === void 0 ? {} : { embedMaxHeightPx }
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
var MAX_CONTENT_HEIGHT_PX = 2e4;
|
|
121
|
+
function parseContentHeight(data) {
|
|
122
|
+
if (!data || typeof data !== "object") {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
const msg = data;
|
|
126
|
+
if (msg.type !== "blink:content-height") {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
const raw = msg.heightPx;
|
|
130
|
+
if (typeof raw !== "number" || !Number.isFinite(raw)) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
const heightPx = Math.round(raw);
|
|
134
|
+
if (heightPx <= 0 || heightPx > MAX_CONTENT_HEIGHT_PX) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
type: "blink:content-height",
|
|
139
|
+
heightPx,
|
|
140
|
+
...parseWidthHint("preferredWidthPx", msg.preferredWidthPx),
|
|
141
|
+
...parseWidthHint("minWidthPx", msg.minWidthPx)
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function parseWidthHint(key, value) {
|
|
145
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return {};
|
|
146
|
+
const px = Math.round(value);
|
|
147
|
+
if (px <= 0 || px > MAX_CONTENT_HEIGHT_PX) return {};
|
|
148
|
+
return { [key]: px };
|
|
114
149
|
}
|
|
115
150
|
function buildRevealMessage() {
|
|
116
151
|
return { type: "blink:reveal" };
|
|
117
152
|
}
|
|
118
|
-
function buildSignedPayloadMessage(merchantId, payload, signature) {
|
|
153
|
+
function buildSignedPayloadMessage(merchantId, payload, signature, balance) {
|
|
119
154
|
return {
|
|
120
155
|
type: "blink:signed-payload",
|
|
121
156
|
merchantId,
|
|
122
157
|
payload,
|
|
123
|
-
signature
|
|
158
|
+
signature,
|
|
159
|
+
...balance === void 0 ? {} : { balance }
|
|
124
160
|
};
|
|
125
161
|
}
|
|
126
162
|
|
|
163
|
+
// src/brandParam.ts
|
|
164
|
+
var BRAND_COLOR_PARAM_KEYS = {
|
|
165
|
+
colorPrimary: "p",
|
|
166
|
+
colorBackground: "bg",
|
|
167
|
+
colorText: "t",
|
|
168
|
+
colorDanger: "d",
|
|
169
|
+
colorBorder: "b"
|
|
170
|
+
};
|
|
171
|
+
function normalizeBrandHex(value) {
|
|
172
|
+
if (typeof value !== "string") return null;
|
|
173
|
+
const hex = value.trim().toLowerCase();
|
|
174
|
+
if (!/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/.test(hex)) return null;
|
|
175
|
+
const digits = hex.slice(1);
|
|
176
|
+
if (digits.length === 6) return `#${digits}`;
|
|
177
|
+
return `#${digits[0]}${digits[0]}${digits[1]}${digits[1]}${digits[2]}${digits[2]}`;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// src/balanceParam.ts
|
|
181
|
+
var MAX_BALANCE_USD = 1e12;
|
|
182
|
+
function normalizeDisplayBalance(value) {
|
|
183
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return null;
|
|
184
|
+
if (value < 0 || value >= MAX_BALANCE_USD) return null;
|
|
185
|
+
const cents = Math.floor(Number((value * 100).toPrecision(15)));
|
|
186
|
+
if (cents < 0 || cents >= MAX_BALANCE_USD * 100) return null;
|
|
187
|
+
return (cents / 100).toFixed(2);
|
|
188
|
+
}
|
|
189
|
+
|
|
127
190
|
// src/walletBridge/discover.ts
|
|
128
191
|
function createWalletDiscoverer() {
|
|
129
192
|
if (typeof window === "undefined") {
|
|
@@ -555,6 +618,84 @@ function measureViewportMetrics() {
|
|
|
555
618
|
}
|
|
556
619
|
}
|
|
557
620
|
|
|
621
|
+
// src/iframeCore.ts
|
|
622
|
+
function createFrameElement(url) {
|
|
623
|
+
const iframe = document.createElement("iframe");
|
|
624
|
+
iframe.src = url;
|
|
625
|
+
const iframeOrigin = new URL(url).origin;
|
|
626
|
+
iframe.allow = `publickey-credentials-get ${iframeOrigin}; publickey-credentials-create ${iframeOrigin}; clipboard-write ${iframeOrigin}; web-share ${iframeOrigin}`;
|
|
627
|
+
return { iframe, iframeOrigin };
|
|
628
|
+
}
|
|
629
|
+
function attachFrameBridges(options) {
|
|
630
|
+
const { iframe, iframeOrigin, postViewport, getEmbedMaxHeightPx, shouldRevealOnLoad } = options;
|
|
631
|
+
let detached = false;
|
|
632
|
+
const discoverer = createWalletDiscoverer();
|
|
633
|
+
let rpcHostHandle = null;
|
|
634
|
+
const attachBridge = () => {
|
|
635
|
+
if (rpcHostHandle) return;
|
|
636
|
+
if (!iframe.contentWindow) return;
|
|
637
|
+
rpcHostHandle = attachRpcHost({
|
|
638
|
+
iframeWindow: iframe.contentWindow,
|
|
639
|
+
iframeOrigin,
|
|
640
|
+
discoverer
|
|
641
|
+
});
|
|
642
|
+
};
|
|
643
|
+
attachBridge();
|
|
644
|
+
iframe.addEventListener("load", attachBridge);
|
|
645
|
+
function postReveal() {
|
|
646
|
+
if (detached) return;
|
|
647
|
+
iframe.contentWindow?.postMessage(buildRevealMessage(), iframeOrigin);
|
|
648
|
+
}
|
|
649
|
+
function postViewportMetrics() {
|
|
650
|
+
if (detached || !postViewport) return;
|
|
651
|
+
const metrics = measureViewportMetrics();
|
|
652
|
+
if (metrics.viewportLvh <= 0) return;
|
|
653
|
+
iframe.contentWindow?.postMessage(
|
|
654
|
+
buildViewportMessage(
|
|
655
|
+
metrics.viewportLvh,
|
|
656
|
+
metrics.safeAreaBottom,
|
|
657
|
+
getEmbedMaxHeightPx?.()
|
|
658
|
+
),
|
|
659
|
+
iframeOrigin
|
|
660
|
+
);
|
|
661
|
+
}
|
|
662
|
+
let viewportPostScheduled = false;
|
|
663
|
+
const onViewportChange = () => {
|
|
664
|
+
if (viewportPostScheduled) return;
|
|
665
|
+
viewportPostScheduled = true;
|
|
666
|
+
requestAnimationFrame(() => {
|
|
667
|
+
viewportPostScheduled = false;
|
|
668
|
+
postViewportMetrics();
|
|
669
|
+
});
|
|
670
|
+
};
|
|
671
|
+
if (postViewport) {
|
|
672
|
+
window.addEventListener("resize", onViewportChange);
|
|
673
|
+
window.addEventListener("orientationchange", onViewportChange);
|
|
674
|
+
}
|
|
675
|
+
const onLoadReveal = () => {
|
|
676
|
+
postViewportMetrics();
|
|
677
|
+
if (shouldRevealOnLoad()) postReveal();
|
|
678
|
+
};
|
|
679
|
+
iframe.addEventListener("load", onLoadReveal);
|
|
680
|
+
return {
|
|
681
|
+
postReveal,
|
|
682
|
+
postViewportMetrics,
|
|
683
|
+
detach() {
|
|
684
|
+
if (detached) return;
|
|
685
|
+
detached = true;
|
|
686
|
+
iframe.removeEventListener("load", attachBridge);
|
|
687
|
+
iframe.removeEventListener("load", onLoadReveal);
|
|
688
|
+
window.removeEventListener("resize", onViewportChange);
|
|
689
|
+
window.removeEventListener("orientationchange", onViewportChange);
|
|
690
|
+
if (rpcHostHandle) {
|
|
691
|
+
rpcHostHandle.detach();
|
|
692
|
+
rpcHostHandle = null;
|
|
693
|
+
}
|
|
694
|
+
discoverer.destroy();
|
|
695
|
+
}
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
|
|
558
699
|
// src/iframe.ts
|
|
559
700
|
var STYLE_ID = "blink-deposit-styles";
|
|
560
701
|
var CLOSE_DURATION_MS = 280;
|
|
@@ -596,60 +737,20 @@ function createIframe(url, containerElement, options) {
|
|
|
596
737
|
}
|
|
597
738
|
const container = document.createElement("div");
|
|
598
739
|
container.setAttribute("data-blink-container", "");
|
|
599
|
-
const iframe =
|
|
600
|
-
iframe.src = url;
|
|
601
|
-
const iframeOrigin = new URL(url).origin;
|
|
602
|
-
iframe.allow = `publickey-credentials-get ${iframeOrigin}; publickey-credentials-create ${iframeOrigin}; clipboard-write ${iframeOrigin}`;
|
|
740
|
+
const { iframe, iframeOrigin } = createFrameElement(url);
|
|
603
741
|
const handle = document.createElement("div");
|
|
604
742
|
container.appendChild(handle);
|
|
605
743
|
container.appendChild(iframe);
|
|
606
744
|
overlay.appendChild(container);
|
|
607
745
|
const mountTarget = containerElement ?? document.body;
|
|
608
746
|
mountTarget.appendChild(overlay);
|
|
609
|
-
const
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
iframeOrigin,
|
|
617
|
-
discoverer
|
|
618
|
-
});
|
|
619
|
-
};
|
|
620
|
-
attachBridge();
|
|
621
|
-
iframe.addEventListener("load", attachBridge);
|
|
622
|
-
function postReveal() {
|
|
623
|
-
if (closed) return;
|
|
624
|
-
iframe.contentWindow?.postMessage(buildRevealMessage(), iframeOrigin);
|
|
625
|
-
}
|
|
626
|
-
function postViewportMetrics() {
|
|
627
|
-
if (closed || !options?.fluid) return;
|
|
628
|
-
const metrics = measureViewportMetrics();
|
|
629
|
-
if (metrics.viewportLvh <= 0) return;
|
|
630
|
-
iframe.contentWindow?.postMessage(
|
|
631
|
-
buildViewportMessage(metrics.viewportLvh, metrics.safeAreaBottom),
|
|
632
|
-
iframeOrigin
|
|
633
|
-
);
|
|
634
|
-
}
|
|
635
|
-
let viewportPostScheduled = false;
|
|
636
|
-
const onViewportChange = () => {
|
|
637
|
-
if (viewportPostScheduled) return;
|
|
638
|
-
viewportPostScheduled = true;
|
|
639
|
-
requestAnimationFrame(() => {
|
|
640
|
-
viewportPostScheduled = false;
|
|
641
|
-
postViewportMetrics();
|
|
642
|
-
});
|
|
643
|
-
};
|
|
644
|
-
if (options?.fluid) {
|
|
645
|
-
window.addEventListener("resize", onViewportChange);
|
|
646
|
-
window.addEventListener("orientationchange", onViewportChange);
|
|
647
|
-
}
|
|
648
|
-
const onLoadReveal = () => {
|
|
649
|
-
postViewportMetrics();
|
|
650
|
-
if (!hidden) postReveal();
|
|
651
|
-
};
|
|
652
|
-
iframe.addEventListener("load", onLoadReveal);
|
|
747
|
+
const bridges = attachFrameBridges({
|
|
748
|
+
iframe,
|
|
749
|
+
iframeOrigin,
|
|
750
|
+
// Only fluid needs them: the legacy fixed overlay sizes the iframe itself.
|
|
751
|
+
postViewport: options?.fluid === true,
|
|
752
|
+
shouldRevealOnLoad: () => !hidden
|
|
753
|
+
});
|
|
653
754
|
let savedOverflow = "";
|
|
654
755
|
let scrollLocked = false;
|
|
655
756
|
const onBackdropClick = (event) => {
|
|
@@ -680,8 +781,6 @@ function createIframe(url, containerElement, options) {
|
|
|
680
781
|
overlay.removeEventListener("click", onBackdropClick);
|
|
681
782
|
overlay.removeEventListener("touchmove", onTouchMove);
|
|
682
783
|
document.removeEventListener("keydown", onKeyDown);
|
|
683
|
-
window.removeEventListener("resize", onViewportChange);
|
|
684
|
-
window.removeEventListener("orientationchange", onViewportChange);
|
|
685
784
|
}
|
|
686
785
|
function unlockScroll() {
|
|
687
786
|
if (!scrollLocked) return;
|
|
@@ -692,7 +791,7 @@ function createIframe(url, containerElement, options) {
|
|
|
692
791
|
if (closed) return;
|
|
693
792
|
closed = true;
|
|
694
793
|
removeListeners();
|
|
695
|
-
|
|
794
|
+
bridges.detach();
|
|
696
795
|
overlay.setAttribute("data-blink-closing", "");
|
|
697
796
|
let removed = false;
|
|
698
797
|
const removeOverlay = () => {
|
|
@@ -705,15 +804,6 @@ function createIframe(url, containerElement, options) {
|
|
|
705
804
|
container.addEventListener("animationend", removeOverlay, { once: true });
|
|
706
805
|
setTimeout(removeOverlay, CLOSE_DURATION_MS + 50);
|
|
707
806
|
}
|
|
708
|
-
function detachBridge() {
|
|
709
|
-
iframe.removeEventListener("load", attachBridge);
|
|
710
|
-
iframe.removeEventListener("load", onLoadReveal);
|
|
711
|
-
if (rpcHostHandle) {
|
|
712
|
-
rpcHostHandle.detach();
|
|
713
|
-
rpcHostHandle = null;
|
|
714
|
-
}
|
|
715
|
-
discoverer.destroy();
|
|
716
|
-
}
|
|
717
807
|
return {
|
|
718
808
|
get contentWindow() {
|
|
719
809
|
return iframe.contentWindow;
|
|
@@ -738,15 +828,17 @@ function createIframe(url, containerElement, options) {
|
|
|
738
828
|
overlay.style.display = "";
|
|
739
829
|
lockScroll();
|
|
740
830
|
attachDismissalListeners();
|
|
741
|
-
postViewportMetrics();
|
|
742
|
-
postReveal();
|
|
831
|
+
bridges.postViewportMetrics();
|
|
832
|
+
bridges.postReveal();
|
|
743
833
|
},
|
|
744
834
|
postReveal() {
|
|
745
|
-
postReveal();
|
|
835
|
+
bridges.postReveal();
|
|
746
836
|
},
|
|
747
837
|
downgradeToFixed() {
|
|
748
838
|
overlay.removeAttribute("data-blink-fluid");
|
|
749
839
|
},
|
|
840
|
+
applyContentHeight() {
|
|
841
|
+
},
|
|
750
842
|
onClose(callback) {
|
|
751
843
|
closeCallback = callback;
|
|
752
844
|
},
|
|
@@ -755,7 +847,7 @@ function createIframe(url, containerElement, options) {
|
|
|
755
847
|
if (!closed) {
|
|
756
848
|
closed = true;
|
|
757
849
|
removeListeners();
|
|
758
|
-
|
|
850
|
+
bridges.detach();
|
|
759
851
|
overlay.remove();
|
|
760
852
|
unlockScroll();
|
|
761
853
|
}
|
|
@@ -792,6 +884,117 @@ function shouldUseMobileSheetLayout() {
|
|
|
792
884
|
return shortestScreenSide > 0 && shortestScreenSide <= MOBILE_SHEET_MAX_SCREEN_PX;
|
|
793
885
|
}
|
|
794
886
|
|
|
887
|
+
// src/embeddedIframe.ts
|
|
888
|
+
var EMBED_STYLE_ID = "blink-deposit-embed-styles";
|
|
889
|
+
var EMBED_STYLES = `
|
|
890
|
+
[data-blink-embed]{display:block;width:100%;position:relative}
|
|
891
|
+
[data-blink-embed][data-blink-embed-hidden]{height:0;overflow:hidden;visibility:hidden;pointer-events:none}
|
|
892
|
+
[data-blink-embed] iframe{display:block;width:100%;height:0;border:none;background:transparent;color-scheme:light}
|
|
893
|
+
`;
|
|
894
|
+
function createEmbeddedIframe(url, containerElement, options) {
|
|
895
|
+
ensureEmbedStyles();
|
|
896
|
+
if (!containerElement.isConnected) {
|
|
897
|
+
console.warn(
|
|
898
|
+
"[blink] The containerElement passed to Deposit is not in the document. Embedded mode renders into it for the life of the instance, so it must be a stable node \u2014 render the slot once and hide it with `visibility: hidden` (NOT `display: none`, which removes its layout and leaves the warming flow unable to measure itself) instead of unmounting it, or construct a new Deposit against the new node."
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
let closed = false;
|
|
902
|
+
let hidden = options?.hidden === true;
|
|
903
|
+
let closeCallback = null;
|
|
904
|
+
const readEmbedMaxHeightPx = () => typeof options?.embedMaxHeightPx === "function" ? options.embedMaxHeightPx() : options?.embedMaxHeightPx;
|
|
905
|
+
const wrapper = document.createElement("div");
|
|
906
|
+
wrapper.setAttribute("data-blink-embed", "");
|
|
907
|
+
if (hidden) {
|
|
908
|
+
wrapper.setAttribute("data-blink-embed-hidden", "");
|
|
909
|
+
}
|
|
910
|
+
const { iframe, iframeOrigin } = createFrameElement(url);
|
|
911
|
+
iframe.setAttribute("scrolling", "no");
|
|
912
|
+
const initialBudget = readEmbedMaxHeightPx();
|
|
913
|
+
if (initialBudget !== void 0) {
|
|
914
|
+
iframe.style.height = `${initialBudget}px`;
|
|
915
|
+
}
|
|
916
|
+
wrapper.appendChild(iframe);
|
|
917
|
+
containerElement.appendChild(wrapper);
|
|
918
|
+
const bridges = attachFrameBridges({
|
|
919
|
+
iframe,
|
|
920
|
+
iframeOrigin,
|
|
921
|
+
// Embedded always needs them: the flow has no usable viewport of its own,
|
|
922
|
+
// so the basis it sizes against can only come from here.
|
|
923
|
+
postViewport: true,
|
|
924
|
+
getEmbedMaxHeightPx: readEmbedMaxHeightPx,
|
|
925
|
+
shouldRevealOnLoad: () => !hidden
|
|
926
|
+
});
|
|
927
|
+
function teardown() {
|
|
928
|
+
closed = true;
|
|
929
|
+
bridges.detach();
|
|
930
|
+
wrapper.remove();
|
|
931
|
+
}
|
|
932
|
+
return {
|
|
933
|
+
get contentWindow() {
|
|
934
|
+
return iframe.contentWindow;
|
|
935
|
+
},
|
|
936
|
+
close() {
|
|
937
|
+
if (closed) return;
|
|
938
|
+
teardown();
|
|
939
|
+
closeCallback?.();
|
|
940
|
+
},
|
|
941
|
+
isClosed() {
|
|
942
|
+
return closed;
|
|
943
|
+
},
|
|
944
|
+
isHidden() {
|
|
945
|
+
return hidden;
|
|
946
|
+
},
|
|
947
|
+
reveal() {
|
|
948
|
+
if (closed || !hidden) return;
|
|
949
|
+
hidden = false;
|
|
950
|
+
wrapper.removeAttribute("data-blink-embed-hidden");
|
|
951
|
+
warnIfContainerNotRendered(containerElement);
|
|
952
|
+
bridges.postViewportMetrics();
|
|
953
|
+
bridges.postReveal();
|
|
954
|
+
},
|
|
955
|
+
postReveal() {
|
|
956
|
+
bridges.postReveal();
|
|
957
|
+
},
|
|
958
|
+
downgradeToFixed() {
|
|
959
|
+
},
|
|
960
|
+
applyContentHeight(heightPx) {
|
|
961
|
+
if (closed) return;
|
|
962
|
+
const budget = readEmbedMaxHeightPx();
|
|
963
|
+
const capped = budget === void 0 ? heightPx : Math.min(heightPx, budget);
|
|
964
|
+
iframe.style.height = `${Math.max(0, Math.round(capped))}px`;
|
|
965
|
+
},
|
|
966
|
+
onClose(callback) {
|
|
967
|
+
closeCallback = callback;
|
|
968
|
+
},
|
|
969
|
+
destroy() {
|
|
970
|
+
closeCallback = null;
|
|
971
|
+
if (!closed) teardown();
|
|
972
|
+
}
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
function warnIfContainerNotRendered(containerElement) {
|
|
976
|
+
if (typeof containerElement.getBoundingClientRect !== "function") return;
|
|
977
|
+
const rect = containerElement.getBoundingClientRect();
|
|
978
|
+
if (rect.width > 0 || rect.height > 0) return;
|
|
979
|
+
const display = typeof getComputedStyle === "function" ? getComputedStyle(containerElement).display : "";
|
|
980
|
+
console.warn(
|
|
981
|
+
`[blink] The containerElement has no layout at the moment the flow is revealed${display === "none" ? " (display: none)" : ""}. A display:none subtree cannot be measured, so the flow may report no height and the panel stays blank at its budget height. Hide the slot with \`visibility: hidden\` (plus \`height: 0; overflow: hidden\`) instead of \`display: none\`, so it keeps its box while it warms up.`
|
|
982
|
+
);
|
|
983
|
+
}
|
|
984
|
+
function ensureEmbedStyles() {
|
|
985
|
+
const existingStyle = document.getElementById(EMBED_STYLE_ID);
|
|
986
|
+
if (existingStyle) {
|
|
987
|
+
if (existingStyle.textContent !== EMBED_STYLES) {
|
|
988
|
+
existingStyle.textContent = EMBED_STYLES;
|
|
989
|
+
}
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
const style = document.createElement("style");
|
|
993
|
+
style.id = EMBED_STYLE_ID;
|
|
994
|
+
style.textContent = EMBED_STYLES;
|
|
995
|
+
document.head.appendChild(style);
|
|
996
|
+
}
|
|
997
|
+
|
|
795
998
|
// src/signer.ts
|
|
796
999
|
var DEFAULT_SIGNER_TIMEOUT_MS = 15e3;
|
|
797
1000
|
async function callSigner(signer, request, timeoutMs) {
|
|
@@ -922,6 +1125,13 @@ var SANDBOX_WEBVIEW_BASE_URL = "https://pay-sandbox.blink.cash";
|
|
|
922
1125
|
var IFRAME_READY_TIMEOUT_MS = 2e3;
|
|
923
1126
|
var WARM_IFRAME_READY_TIMEOUT_MS = 6e4;
|
|
924
1127
|
var LAYOUT_FLUID_CAPABILITY = "layout-fluid";
|
|
1128
|
+
var DEFAULT_EMBED_MAX_HEIGHT_FRACTION = 0.9;
|
|
1129
|
+
function dismissedError() {
|
|
1130
|
+
return new DepositError(
|
|
1131
|
+
"DEPOSIT_DISMISSED",
|
|
1132
|
+
"The deposit was dismissed before the transfer completed."
|
|
1133
|
+
);
|
|
1134
|
+
}
|
|
925
1135
|
var IFRAME_NOT_READY = { ready: false, fluidCapable: false };
|
|
926
1136
|
function resolveWebviewBaseUrl(config) {
|
|
927
1137
|
if (config.webviewBaseUrl) return config.webviewBaseUrl;
|
|
@@ -942,11 +1152,20 @@ var Deposit = class {
|
|
|
942
1152
|
warmIframe = null;
|
|
943
1153
|
warmIframeReady = null;
|
|
944
1154
|
warmIframeReadyCancel = null;
|
|
1155
|
+
/** Resolved embedded-vs-overlay decision; see {@link Deposit.isEmbedded}. */
|
|
1156
|
+
embeddedResolved = null;
|
|
1157
|
+
/**
|
|
1158
|
+
* Settles the in-flight `requestDeposit()` as a dismissal. Non-null exactly
|
|
1159
|
+
* while a flow is in progress, so {@link Deposit.close} can reject the promise
|
|
1160
|
+
* the caller is awaiting instead of tearing the frame down under it.
|
|
1161
|
+
*/
|
|
1162
|
+
dismissActiveFlow = null;
|
|
945
1163
|
listeners = {
|
|
946
1164
|
complete: /* @__PURE__ */ new Set(),
|
|
947
1165
|
error: /* @__PURE__ */ new Set(),
|
|
948
1166
|
close: /* @__PURE__ */ new Set(),
|
|
949
|
-
"status-change": /* @__PURE__ */ new Set()
|
|
1167
|
+
"status-change": /* @__PURE__ */ new Set(),
|
|
1168
|
+
resize: /* @__PURE__ */ new Set()
|
|
950
1169
|
};
|
|
951
1170
|
/** Current phase of the deposit flow. */
|
|
952
1171
|
get status() {
|
|
@@ -964,10 +1183,40 @@ var Deposit = class {
|
|
|
964
1183
|
get isActive() {
|
|
965
1184
|
return this._status === "signer-loading" || this._status === "iframe-active";
|
|
966
1185
|
}
|
|
1186
|
+
/**
|
|
1187
|
+
* How this instance will actually present: `'embedded'` renders inline in
|
|
1188
|
+
* `containerElement`, `'overlay'` covers the page.
|
|
1189
|
+
*
|
|
1190
|
+
* Not simply an echo of the config — a host that asked for `'embedded'` gets
|
|
1191
|
+
* `'overlay'` on mobile, where a phone-sized method panel cannot hold the
|
|
1192
|
+
* flow (see {@link Deposit.isEmbedded}). Read it when laying out the panel:
|
|
1193
|
+
* on `'overlay'` no `resize` event ever fires, so a panel sized from those
|
|
1194
|
+
* reports would sit empty behind the overlay — collapse or skip it.
|
|
1195
|
+
*
|
|
1196
|
+
* Live until the SDK builds its first (warm-up) frame and fixed from then on,
|
|
1197
|
+
* so re-read it on resize rather than caching it at mount.
|
|
1198
|
+
*/
|
|
1199
|
+
get presentation() {
|
|
1200
|
+
return this.isEmbedded() ? "embedded" : "overlay";
|
|
1201
|
+
}
|
|
967
1202
|
constructor(config) {
|
|
968
1203
|
if (!config.signer || typeof config.signer !== "string" && typeof config.signer !== "function") {
|
|
969
1204
|
throw new DepositError("INVALID_REQUEST", "DepositConfig.signer is required (URL string or SignerFunction).");
|
|
970
1205
|
}
|
|
1206
|
+
if (config.presentation === "embedded") {
|
|
1207
|
+
if (!config.containerElement) {
|
|
1208
|
+
throw new DepositError(
|
|
1209
|
+
"INVALID_REQUEST",
|
|
1210
|
+
'DepositConfig.containerElement is required when presentation is "embedded".'
|
|
1211
|
+
);
|
|
1212
|
+
}
|
|
1213
|
+
if (config.layout === "fixed") {
|
|
1214
|
+
throw new DepositError(
|
|
1215
|
+
"INVALID_REQUEST",
|
|
1216
|
+
'DepositConfig.layout "fixed" is an overlay-only escape hatch and cannot be combined with presentation "embedded".'
|
|
1217
|
+
);
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
971
1220
|
this.config = config;
|
|
972
1221
|
this.log("Deposit instance created", {
|
|
973
1222
|
signer: typeof config.signer === "string" ? config.signer : "<function>"
|
|
@@ -993,10 +1242,7 @@ var Deposit = class {
|
|
|
993
1242
|
const webviewBaseUrl = resolveWebviewBaseUrl(this.config);
|
|
994
1243
|
this.hostedOrigin = this.config.hostedFlowOrigin ?? new URL(webviewBaseUrl).origin;
|
|
995
1244
|
const preloadUrl = this.buildPreloadUrl(webviewBaseUrl);
|
|
996
|
-
const iframe =
|
|
997
|
-
hidden: true,
|
|
998
|
-
fluid: this.isFluidLayout()
|
|
999
|
-
});
|
|
1245
|
+
const iframe = this.createPresentedIframe(preloadUrl, { hidden: true });
|
|
1000
1246
|
const ready = this.waitForIframeReady(iframe, WARM_IFRAME_READY_TIMEOUT_MS);
|
|
1001
1247
|
this.warmIframe = iframe;
|
|
1002
1248
|
this.warmIframeReady = ready.promise;
|
|
@@ -1025,6 +1271,83 @@ var Deposit = class {
|
|
|
1025
1271
|
window.addEventListener("load", whenIdle, { once: true });
|
|
1026
1272
|
}
|
|
1027
1273
|
}
|
|
1274
|
+
/**
|
|
1275
|
+
* Whether the flow renders inline in the host's element rather than as an
|
|
1276
|
+
* overlay.
|
|
1277
|
+
*
|
|
1278
|
+
* `presentation: 'embedded'` is a request, not a guarantee: **on mobile the
|
|
1279
|
+
* flow presents as the normal overlay** even for an embedded host. An
|
|
1280
|
+
* aggregator's method panel is a narrow, short column on a phone, and the
|
|
1281
|
+
* flow inside it is a payment journey with a keypad, wallet lists and a QR
|
|
1282
|
+
* code — it needs the screen. The overlay is exactly what a phone user gets
|
|
1283
|
+
* from every other Blink integration, and the host's own dialog stays behind
|
|
1284
|
+
* it. Desktop keeps the inline card, where the panel has room.
|
|
1285
|
+
*
|
|
1286
|
+
* **The decision lives with the frame.** Read live until a frame is built,
|
|
1287
|
+
* then committed for good ({@link Deposit.createPresentedIframe}) — `preload()`
|
|
1288
|
+
* warms a frame from these same predicates and the flow that later adopts it
|
|
1289
|
+
* must agree, because a frame warmed at `layout=embed` handed to the overlay
|
|
1290
|
+
* presenter (or the reverse) is a blank modal. Committing at frame creation
|
|
1291
|
+
* rather than at construction matters: a host that constructs `Deposit` before
|
|
1292
|
+
* layout settles — a widget mounting inside a transition, a background or
|
|
1293
|
+
* prerendered tab — reports a zero-width viewport, and `(max-width: 640px)`
|
|
1294
|
+
* matches at zero, so caching then would lock a desktop user into the overlay
|
|
1295
|
+
* over a viewport that never existed. The warm-up already waits for `load`
|
|
1296
|
+
* plus an idle callback, so by the time it commits the measurement is real.
|
|
1297
|
+
*/
|
|
1298
|
+
isEmbedded() {
|
|
1299
|
+
if (this.config.presentation !== "embedded") return false;
|
|
1300
|
+
if (this.embeddedResolved !== null) return this.embeddedResolved;
|
|
1301
|
+
if (typeof window === "undefined") return true;
|
|
1302
|
+
const viewportWidth = window.visualViewport?.width ?? window.innerWidth;
|
|
1303
|
+
if (!(viewportWidth > 0)) return true;
|
|
1304
|
+
return !shouldUseMobileSheetLayout();
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* The host's height budget for the inline iframe. Explicit config wins;
|
|
1308
|
+
* otherwise most of the host viewport, which keeps a tall flow from
|
|
1309
|
+
* outgrowing the page it is embedded in.
|
|
1310
|
+
*/
|
|
1311
|
+
resolveEmbedMaxHeightPx() {
|
|
1312
|
+
if (this.config.embedMaxHeightPx !== void 0) return this.config.embedMaxHeightPx;
|
|
1313
|
+
if (typeof window === "undefined") return void 0;
|
|
1314
|
+
const derived = Math.round(window.innerHeight * DEFAULT_EMBED_MAX_HEIGHT_FRACTION);
|
|
1315
|
+
return derived > 0 ? derived : void 0;
|
|
1316
|
+
}
|
|
1317
|
+
/** Build the iframe for the configured presentation. */
|
|
1318
|
+
createPresentedIframe(url, options) {
|
|
1319
|
+
if (this.config.presentation === "embedded" && this.embeddedResolved === null) {
|
|
1320
|
+
this.embeddedResolved = this.isEmbedded();
|
|
1321
|
+
if (!this.embeddedResolved) {
|
|
1322
|
+
this.log("Mobile device: presenting the embedded flow as an overlay");
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
if (this.isEmbedded()) {
|
|
1326
|
+
return createEmbeddedIframe(url, this.config.containerElement, {
|
|
1327
|
+
hidden: options.hidden,
|
|
1328
|
+
// A getter, not a value: the default is derived from the host
|
|
1329
|
+
// viewport, which changes on rotation and window resize.
|
|
1330
|
+
embedMaxHeightPx: () => this.resolveEmbedMaxHeightPx()
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
return createIframe(url, this.overlayMountTarget(), {
|
|
1334
|
+
hidden: options.hidden,
|
|
1335
|
+
fluid: this.isFluidLayout()
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Where the overlay mounts. `containerElement` means two different things by
|
|
1340
|
+
* presentation: an overlay mount point (`presentation: 'overlay'`) or the
|
|
1341
|
+
* aggregator's inline panel slot (`'embedded'`). When an embedded flow
|
|
1342
|
+
* presents as an overlay on mobile, that slot must NOT be the mount point —
|
|
1343
|
+
* `position: fixed` resolves against the nearest transformed/filtered/
|
|
1344
|
+
* contained ancestor, and an aggregator's animated dialog is exactly that, so
|
|
1345
|
+
* the "full-screen" overlay would end up positioned inside their panel.
|
|
1346
|
+
* Falls through to `document.body`.
|
|
1347
|
+
*/
|
|
1348
|
+
overlayMountTarget() {
|
|
1349
|
+
return this.config.presentation === "embedded" ? void 0 : this.config.containerElement;
|
|
1350
|
+
}
|
|
1028
1351
|
buildPreloadUrl(webviewBaseUrl) {
|
|
1029
1352
|
const preloadUrl = new URL(webviewBaseUrl);
|
|
1030
1353
|
preloadUrl.searchParams.set("preload", "true");
|
|
@@ -1090,6 +1413,7 @@ var Deposit = class {
|
|
|
1090
1413
|
const settle = (fn) => {
|
|
1091
1414
|
if (this.requestId !== currentRequestId || settled) return;
|
|
1092
1415
|
settled = true;
|
|
1416
|
+
this.dismissActiveFlow = null;
|
|
1093
1417
|
fn();
|
|
1094
1418
|
};
|
|
1095
1419
|
const onComplete = (result) => {
|
|
@@ -1115,6 +1439,12 @@ var Deposit = class {
|
|
|
1115
1439
|
reject(error);
|
|
1116
1440
|
});
|
|
1117
1441
|
};
|
|
1442
|
+
this.dismissActiveFlow = () => {
|
|
1443
|
+
settle(() => {
|
|
1444
|
+
this.cleanup();
|
|
1445
|
+
reject(dismissedError());
|
|
1446
|
+
});
|
|
1447
|
+
};
|
|
1118
1448
|
if (this.config.flowTimeoutMs != null && this.config.flowTimeoutMs > 0) {
|
|
1119
1449
|
this.flowTimer = setTimeout(() => {
|
|
1120
1450
|
onError(
|
|
@@ -1141,9 +1471,29 @@ var Deposit = class {
|
|
|
1141
1471
|
/** No-op — retained for API compatibility with the popup-based SDK. */
|
|
1142
1472
|
focus() {
|
|
1143
1473
|
}
|
|
1144
|
-
/**
|
|
1474
|
+
/**
|
|
1475
|
+
* Close the deposit iframe without waiting for completion — the host's own
|
|
1476
|
+
* back button or dialog chrome.
|
|
1477
|
+
*
|
|
1478
|
+
* This **settles a flow in progress** by rejecting its `requestDeposit()`
|
|
1479
|
+
* promise with `DEPOSIT_DISMISSED`, exactly as the flow's own close control
|
|
1480
|
+
* does. It has to: `cleanup()` destroys the frame through `destroy()`, which
|
|
1481
|
+
* drops the handle's close callback on purpose, so without this the caller's
|
|
1482
|
+
* `await` never returns. An aggregator whose back button awaited that promise
|
|
1483
|
+
* to restore its method list was left showing an empty panel — the flow gone,
|
|
1484
|
+
* its own list still not rendered, and no error to explain why.
|
|
1485
|
+
*
|
|
1486
|
+
* The rejection code is the same `DEPOSIT_DISMISSED` the in-flow control
|
|
1487
|
+
* produces, so a host writes one dismissal branch rather than one per
|
|
1488
|
+
* affordance. What it deliberately does not do is report an error: no `error`
|
|
1489
|
+
* event, and `status` lands on 'idle' as it always has, because the host
|
|
1490
|
+
* initiated this. With no flow in progress it is a plain teardown, unchanged.
|
|
1491
|
+
*/
|
|
1145
1492
|
close() {
|
|
1146
1493
|
this.log("close() called");
|
|
1494
|
+
const dismiss = this.dismissActiveFlow;
|
|
1495
|
+
this.dismissActiveFlow = null;
|
|
1496
|
+
dismiss?.();
|
|
1147
1497
|
this.cleanup();
|
|
1148
1498
|
this.setStatus("idle");
|
|
1149
1499
|
this.emit("close");
|
|
@@ -1196,10 +1546,80 @@ var Deposit = class {
|
|
|
1196
1546
|
if (theme === "dark" || theme === "system") {
|
|
1197
1547
|
url.searchParams.set("appearance", theme);
|
|
1198
1548
|
}
|
|
1549
|
+
this.applyBrandParam(url);
|
|
1199
1550
|
}
|
|
1200
|
-
/**
|
|
1551
|
+
/**
|
|
1552
|
+
* Appends the merchant's brand colors as `brand=p-0f62fe.bg-ffffff…`.
|
|
1553
|
+
*
|
|
1554
|
+
* On the URL rather than a message because the hosted flow's loading shell
|
|
1555
|
+
* paints from its entry chunk, hundreds of ms before React mounts: a palette
|
|
1556
|
+
* that arrived by `postMessage` would show Blink's own card color first and
|
|
1557
|
+
* then become the merchant's. Unreserved characters only, so the param costs
|
|
1558
|
+
* ~50 bytes of the URL budget rather than triple that in percent-encoding.
|
|
1559
|
+
*
|
|
1560
|
+
* Validated here purely so the merchant sees the complaint in their OWN
|
|
1561
|
+
* console — the hosted flow re-validates everything it decodes, since the URL
|
|
1562
|
+
* is host-controlled input that ends up in a stylesheet. Silence would be the
|
|
1563
|
+
* worst outcome: a dropped color that nobody is told about looks like the SDK
|
|
1564
|
+
* ignoring the config.
|
|
1565
|
+
*/
|
|
1566
|
+
applyBrandParam(url) {
|
|
1567
|
+
const variables = this.config.appearance?.variables;
|
|
1568
|
+
if (!variables) return;
|
|
1569
|
+
const accepted = {};
|
|
1570
|
+
for (const [key, value] of Object.entries(variables)) {
|
|
1571
|
+
if (value === void 0 || value === null) continue;
|
|
1572
|
+
if (!BRAND_COLOR_PARAM_KEYS[key]) {
|
|
1573
|
+
console.error(
|
|
1574
|
+
`[blink] appearance.variables.${key} is not a supported brand color. Supported: ${Object.keys(BRAND_COLOR_PARAM_KEYS).join(", ")}.`
|
|
1575
|
+
);
|
|
1576
|
+
continue;
|
|
1577
|
+
}
|
|
1578
|
+
const hex = normalizeBrandHex(value);
|
|
1579
|
+
if (!hex) {
|
|
1580
|
+
console.error(
|
|
1581
|
+
`[blink] appearance.variables.${key} must be opaque hex (#rgb or #rrggbb); received ${JSON.stringify(value)}. Ignoring it.`
|
|
1582
|
+
);
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
accepted[key] = hex;
|
|
1586
|
+
}
|
|
1587
|
+
const encoded = Object.keys(BRAND_COLOR_PARAM_KEYS).filter((key) => accepted[key] !== void 0).map((key) => `${BRAND_COLOR_PARAM_KEYS[key]}-${accepted[key].slice(1)}`).join(".");
|
|
1588
|
+
if (encoded) url.searchParams.set("brand", encoded);
|
|
1589
|
+
}
|
|
1590
|
+
/**
|
|
1591
|
+
* Normalizes the display-only {@link DepositRequest.balance} for the wire,
|
|
1592
|
+
* or returns `undefined` to omit it everywhere — the `blink:signed-payload`
|
|
1593
|
+
* sibling field and the legacy fallback URL param alike. Additive wire
|
|
1594
|
+
* discipline: an unset or rejected balance leaves both channels
|
|
1595
|
+
* byte-for-byte what they always were, and old webviews ignore the field
|
|
1596
|
+
* by construction.
|
|
1597
|
+
*
|
|
1598
|
+
* Validated here purely so the merchant sees the complaint in their OWN
|
|
1599
|
+
* console (same rationale as {@link applyBrandParam}); the hosted flow
|
|
1600
|
+
* re-validates whatever arrives, since both channels are host-controlled
|
|
1601
|
+
* input. A rejected balance never blocks the deposit — the flow proceeds
|
|
1602
|
+
* without the subtitle.
|
|
1603
|
+
*/
|
|
1604
|
+
normalizeRequestBalance(balance) {
|
|
1605
|
+
if (balance === void 0 || balance === null) return void 0;
|
|
1606
|
+
const normalized = normalizeDisplayBalance(balance);
|
|
1607
|
+
if (normalized === null) {
|
|
1608
|
+
const received = typeof balance === "number" ? String(balance) : JSON.stringify(balance) ?? String(balance);
|
|
1609
|
+
console.error(
|
|
1610
|
+
`[blink] balance must be a finite number >= 0 and < 1e12 (USD, display only); received ${received}. Ignoring it.`
|
|
1611
|
+
);
|
|
1612
|
+
return void 0;
|
|
1613
|
+
}
|
|
1614
|
+
return normalized;
|
|
1615
|
+
}
|
|
1616
|
+
/**
|
|
1617
|
+
* Fluid is the default; `layout: 'fixed'` opts back into the legacy
|
|
1618
|
+
* container. Embedded is a separate presentation and never fluid — the
|
|
1619
|
+
* constructor rejects the combination outright.
|
|
1620
|
+
*/
|
|
1201
1621
|
isFluidLayout() {
|
|
1202
|
-
return this.config.layout !== "fixed";
|
|
1622
|
+
return !this.isEmbedded() && this.config.layout !== "fixed";
|
|
1203
1623
|
}
|
|
1204
1624
|
/**
|
|
1205
1625
|
* Marks the hosted-flow URL as fluid-layout: the iframe spans the full
|
|
@@ -1209,6 +1629,10 @@ var Deposit = class {
|
|
|
1209
1629
|
* assumed to understand fluid layout and gets the fixed container.
|
|
1210
1630
|
*/
|
|
1211
1631
|
applyLayoutParam(url) {
|
|
1632
|
+
if (this.isEmbedded()) {
|
|
1633
|
+
url.searchParams.set("layout", "embed");
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1212
1636
|
if (this.isFluidLayout()) {
|
|
1213
1637
|
url.searchParams.set("layout", "fluid");
|
|
1214
1638
|
}
|
|
@@ -1220,7 +1644,14 @@ var Deposit = class {
|
|
|
1220
1644
|
* afterwards (rotation, window resize) — see iframe.ts.
|
|
1221
1645
|
*/
|
|
1222
1646
|
applyViewportParams(url) {
|
|
1223
|
-
|
|
1647
|
+
const embedded = this.isEmbedded();
|
|
1648
|
+
if (!this.isFluidLayout() && !embedded) return;
|
|
1649
|
+
if (embedded) {
|
|
1650
|
+
const embedMaxHeightPx = this.resolveEmbedMaxHeightPx();
|
|
1651
|
+
if (embedMaxHeightPx !== void 0) {
|
|
1652
|
+
url.searchParams.set("embedMaxHeight", String(embedMaxHeightPx));
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1224
1655
|
const metrics = measureViewportMetrics();
|
|
1225
1656
|
if (metrics.viewportLvh <= 0) return;
|
|
1226
1657
|
url.searchParams.set("viewportLvh", String(metrics.viewportLvh));
|
|
@@ -1240,6 +1671,7 @@ var Deposit = class {
|
|
|
1240
1671
|
signer: typeof this.config.signer === "string" ? this.config.signer : "<function>"
|
|
1241
1672
|
});
|
|
1242
1673
|
const signerRequest = buildSignerRequest(request, webviewBaseUrl);
|
|
1674
|
+
const displayBalance = this.normalizeRequestBalance(request.balance);
|
|
1243
1675
|
let preloadIframe;
|
|
1244
1676
|
let iframeReadyPromise;
|
|
1245
1677
|
const warm = this.takeWarmIframe();
|
|
@@ -1257,21 +1689,12 @@ var Deposit = class {
|
|
|
1257
1689
|
});
|
|
1258
1690
|
this.log("Reusing warm preload iframe");
|
|
1259
1691
|
} else {
|
|
1260
|
-
preloadIframe =
|
|
1261
|
-
this.buildPreloadUrl(webviewBaseUrl),
|
|
1262
|
-
this.config.containerElement,
|
|
1263
|
-
{ fluid: this.isFluidLayout() }
|
|
1264
|
-
);
|
|
1692
|
+
preloadIframe = this.createPresentedIframe(this.buildPreloadUrl(webviewBaseUrl), {});
|
|
1265
1693
|
iframeReadyPromise = this.waitForIframeReady(preloadIframe).promise;
|
|
1266
1694
|
}
|
|
1267
1695
|
this.iframe = preloadIframe;
|
|
1268
1696
|
preloadIframe.onClose(() => {
|
|
1269
|
-
onError(
|
|
1270
|
-
new DepositError(
|
|
1271
|
-
"DEPOSIT_DISMISSED",
|
|
1272
|
-
"The deposit was dismissed before the transfer completed."
|
|
1273
|
-
)
|
|
1274
|
-
);
|
|
1697
|
+
onError(dismissedError());
|
|
1275
1698
|
this.cleanup();
|
|
1276
1699
|
this.emit("close");
|
|
1277
1700
|
});
|
|
@@ -1301,7 +1724,8 @@ var Deposit = class {
|
|
|
1301
1724
|
buildSignedPayloadMessage(
|
|
1302
1725
|
signerResponse.merchantId,
|
|
1303
1726
|
signerResponse.payload,
|
|
1304
|
-
signerResponse.signature
|
|
1727
|
+
signerResponse.signature,
|
|
1728
|
+
displayBalance
|
|
1305
1729
|
),
|
|
1306
1730
|
this.hostedOrigin
|
|
1307
1731
|
);
|
|
@@ -1315,17 +1739,19 @@ var Deposit = class {
|
|
|
1315
1739
|
hostedUrl.searchParams.set("merchantId", signerResponse.merchantId);
|
|
1316
1740
|
hostedUrl.searchParams.set("payload", signerResponse.payload);
|
|
1317
1741
|
hostedUrl.searchParams.set("signature", signerResponse.signature);
|
|
1742
|
+
if (displayBalance !== void 0) {
|
|
1743
|
+
hostedUrl.searchParams.set("balance", displayBalance);
|
|
1744
|
+
}
|
|
1318
1745
|
this.applyFullWidgetParam(hostedUrl);
|
|
1746
|
+
if (this.isEmbedded()) {
|
|
1747
|
+
this.applyLayoutParam(hostedUrl);
|
|
1748
|
+
this.applyViewportParams(hostedUrl);
|
|
1749
|
+
}
|
|
1319
1750
|
const targetUrl = hostedUrl.toString();
|
|
1320
|
-
const iframeHandle =
|
|
1751
|
+
const iframeHandle = this.createPresentedIframe(targetUrl, {});
|
|
1321
1752
|
this.iframe = iframeHandle;
|
|
1322
1753
|
iframeHandle.onClose(() => {
|
|
1323
|
-
onError(
|
|
1324
|
-
new DepositError(
|
|
1325
|
-
"DEPOSIT_DISMISSED",
|
|
1326
|
-
"The deposit was dismissed before the transfer completed."
|
|
1327
|
-
)
|
|
1328
|
-
);
|
|
1754
|
+
onError(dismissedError());
|
|
1329
1755
|
this.cleanup();
|
|
1330
1756
|
this.emit("close");
|
|
1331
1757
|
});
|
|
@@ -1401,6 +1827,16 @@ var Deposit = class {
|
|
|
1401
1827
|
iframeHandle.close();
|
|
1402
1828
|
return;
|
|
1403
1829
|
}
|
|
1830
|
+
const contentHeight = parseContentHeight(event.data);
|
|
1831
|
+
if (contentHeight) {
|
|
1832
|
+
iframeHandle.applyContentHeight(contentHeight.heightPx);
|
|
1833
|
+
this.emit("resize", {
|
|
1834
|
+
heightPx: contentHeight.heightPx,
|
|
1835
|
+
...contentHeight.preferredWidthPx === void 0 ? {} : { preferredWidthPx: contentHeight.preferredWidthPx },
|
|
1836
|
+
...contentHeight.minWidthPx === void 0 ? {} : { minWidthPx: contentHeight.minWidthPx }
|
|
1837
|
+
});
|
|
1838
|
+
return;
|
|
1839
|
+
}
|
|
1404
1840
|
const message = parseTransferComplete(event.data);
|
|
1405
1841
|
if (!message) {
|
|
1406
1842
|
return;
|