@swype-org/deposit 0.3.14 → 0.3.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.cjs CHANGED
@@ -93,6 +93,24 @@ function parseCloseRequest(data) {
93
93
  }
94
94
  return { type: "blink:close-request" };
95
95
  }
96
+ function parseIframeReady(data) {
97
+ if (!data || typeof data !== "object") {
98
+ return null;
99
+ }
100
+ const msg = data;
101
+ if (msg.type !== "blink:iframe-ready") {
102
+ return null;
103
+ }
104
+ return { type: "blink:iframe-ready" };
105
+ }
106
+ function buildSignedPayloadMessage(merchantId, payload, signature) {
107
+ return {
108
+ type: "blink:signed-payload",
109
+ merchantId,
110
+ payload,
111
+ signature
112
+ };
113
+ }
96
114
 
97
115
  // src/walletBridge/discover.ts
98
116
  function createWalletDiscoverer() {
@@ -233,7 +251,13 @@ var ALLOWED_RPC_METHODS = /* @__PURE__ */ new Set([
233
251
  "wallet_addEthereumChain",
234
252
  "wallet_switchEthereumChain",
235
253
  "wallet_sendCalls",
236
- "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"
237
261
  ]);
238
262
  var FORWARDED_PROVIDER_EVENTS = [
239
263
  "accountsChanged",
@@ -921,30 +945,16 @@ var Deposit = class {
921
945
  async runSignerFlow(request, requestId, onComplete, onError) {
922
946
  try {
923
947
  const webviewBaseUrl = this.config.webviewBaseUrl ?? DEFAULT_WEBVIEW_BASE_URL;
948
+ this.hostedOrigin = this.config.hostedFlowOrigin ?? new URL(webviewBaseUrl).origin;
924
949
  this.log("Calling signer", {
925
950
  signer: typeof this.config.signer === "string" ? this.config.signer : "<function>"
926
951
  });
927
952
  const signerRequest = buildSignerRequest(request, webviewBaseUrl);
928
- const signerResponse = await callSigner(
929
- this.config.signer,
930
- signerRequest,
931
- this.config.signerTimeoutMs
932
- );
933
- this.lastSignerResponse = signerResponse;
934
- this.log("Signer responded", { merchantId: signerResponse.merchantId });
935
- if (this.requestId !== requestId) {
936
- this.log("Request superseded after signer response");
937
- return;
938
- }
939
- const hostedUrl = new URL(webviewBaseUrl);
940
- hostedUrl.searchParams.set("merchantId", signerResponse.merchantId);
941
- hostedUrl.searchParams.set("payload", signerResponse.payload);
942
- hostedUrl.searchParams.set("signature", signerResponse.signature);
943
- const targetUrl = hostedUrl.toString();
944
- this.hostedOrigin = this.config.hostedFlowOrigin ?? hostedUrl.origin;
945
- const iframeHandle = createIframe(targetUrl, this.config.containerElement);
946
- this.iframe = iframeHandle;
947
- iframeHandle.onClose(() => {
953
+ const preloadUrl = new URL(webviewBaseUrl);
954
+ preloadUrl.searchParams.set("preload", "true");
955
+ const preloadIframe = createIframe(preloadUrl.toString(), this.config.containerElement);
956
+ this.iframe = preloadIframe;
957
+ preloadIframe.onClose(() => {
948
958
  onError(
949
959
  new DepositError(
950
960
  "DEPOSIT_DISMISSED",
@@ -954,9 +964,60 @@ var Deposit = class {
954
964
  this.cleanup();
955
965
  this.emit("close");
956
966
  });
957
- this.startMessageListener(iframeHandle, onComplete);
958
- this.setStatus("iframe-active");
959
- this.log("Iframe opened with hosted flow", { url: targetUrl });
967
+ const signerPromise = callSigner(
968
+ this.config.signer,
969
+ signerRequest,
970
+ this.config.signerTimeoutMs
971
+ );
972
+ const iframeReadyPromise = this.waitForIframeReady(preloadIframe);
973
+ const [signerResponse, iframeReady] = await Promise.all([
974
+ signerPromise,
975
+ iframeReadyPromise
976
+ ]);
977
+ this.lastSignerResponse = signerResponse;
978
+ this.log("Signer responded", { merchantId: signerResponse.merchantId });
979
+ if (this.requestId !== requestId || preloadIframe.isClosed()) {
980
+ this.log("Request superseded or iframe dismissed during signer call");
981
+ return;
982
+ }
983
+ if (iframeReady) {
984
+ const contentWindow = preloadIframe.contentWindow;
985
+ if (contentWindow) {
986
+ contentWindow.postMessage(
987
+ buildSignedPayloadMessage(
988
+ signerResponse.merchantId,
989
+ signerResponse.payload,
990
+ signerResponse.signature
991
+ ),
992
+ this.hostedOrigin
993
+ );
994
+ }
995
+ this.startMessageListener(preloadIframe, onComplete);
996
+ this.setStatus("iframe-active");
997
+ this.log("Payload delivered via postMessage (preload path)");
998
+ } else {
999
+ preloadIframe.destroy();
1000
+ const hostedUrl = new URL(webviewBaseUrl);
1001
+ hostedUrl.searchParams.set("merchantId", signerResponse.merchantId);
1002
+ hostedUrl.searchParams.set("payload", signerResponse.payload);
1003
+ hostedUrl.searchParams.set("signature", signerResponse.signature);
1004
+ const targetUrl = hostedUrl.toString();
1005
+ const iframeHandle = createIframe(targetUrl, this.config.containerElement);
1006
+ this.iframe = iframeHandle;
1007
+ iframeHandle.onClose(() => {
1008
+ onError(
1009
+ new DepositError(
1010
+ "DEPOSIT_DISMISSED",
1011
+ "The deposit was dismissed before the transfer completed."
1012
+ )
1013
+ );
1014
+ this.cleanup();
1015
+ this.emit("close");
1016
+ });
1017
+ this.startMessageListener(iframeHandle, onComplete);
1018
+ this.setStatus("iframe-active");
1019
+ this.log("Iframe opened with hosted flow (fallback path)", { url: targetUrl });
1020
+ }
960
1021
  } catch (err) {
961
1022
  if (this.requestId !== requestId) return;
962
1023
  this.log("Signer flow failed", { error: err instanceof Error ? err.message : String(err) });
@@ -972,6 +1033,25 @@ var Deposit = class {
972
1033
  }
973
1034
  }
974
1035
  }
1036
+ waitForIframeReady(iframeHandle) {
1037
+ return new Promise((resolve) => {
1038
+ const handler = (event) => {
1039
+ if (event.origin !== this.hostedOrigin) return;
1040
+ if (event.source !== iframeHandle.contentWindow) return;
1041
+ if (parseIframeReady(event.data)) {
1042
+ window.removeEventListener("message", handler);
1043
+ clearTimeout(timeout);
1044
+ resolve(true);
1045
+ }
1046
+ };
1047
+ window.addEventListener("message", handler);
1048
+ const timeout = setTimeout(() => {
1049
+ window.removeEventListener("message", handler);
1050
+ this.log("Iframe ready timeout \u2014 falling back to URL params");
1051
+ resolve(false);
1052
+ }, 2e3);
1053
+ });
1054
+ }
975
1055
  startMessageListener(iframeHandle, onComplete) {
976
1056
  const handler = (event) => {
977
1057
  if (this.hostedOrigin && event.origin !== this.hostedOrigin) {