@swype-org/deposit 0.3.20 → 0.3.22

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/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { D as DepositStatus, a as DepositResult, b as DepositError, c as DepositConfig, d as DepositRequest } from './types-Ds07N2zN.cjs';
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.cjs';
1
+ import { D as DepositStatus, a as DepositResult, b as DepositError, c as DepositConfig, d as DepositRequest } from './types-iQf3f-_m.cjs';
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-iQf3f-_m.cjs';
3
3
 
4
4
  declare const DEFAULT_WEBVIEW_BASE_URL = "https://pay.blink.cash";
5
5
  declare const SANDBOX_WEBVIEW_BASE_URL = "https://pay-sandbox.blink.cash";
@@ -94,11 +94,30 @@ declare class Deposit {
94
94
  * config, so the full widget renders only when both allow it.
95
95
  */
96
96
  private applyFullWidgetParam;
97
+ /** Fluid is the default; `layout: 'fixed'` opts back into the legacy container. */
98
+ private isFluidLayout;
99
+ /**
100
+ * Marks the hosted-flow URL as fluid-layout: the iframe spans the full
101
+ * viewport and the hosted flow renders the card/sheet chrome itself.
102
+ * Only applied to preload URLs — the URL-param fallback path exists
103
+ * precisely because the webview never signalled ready, so it cannot be
104
+ * assumed to understand fluid layout and gets the fixed container.
105
+ */
106
+ private applyLayoutParam;
107
+ /**
108
+ * Seeds the merchant page's large-viewport height and safe-area bottom
109
+ * inset onto the fluid preload URL so the hosted flow can size the sheet
110
+ * before its JS boots. `blink:viewport` messages keep the values fresh
111
+ * afterwards (rotation, window resize) — see iframe.ts.
112
+ */
113
+ private applyViewportParams;
97
114
  private setStatus;
98
115
  private runSignerFlow;
99
116
  /**
100
- * Resolves true when the iframe posts `blink:iframe-ready`, false on
101
- * timeout. `cancel()` settles the promise as false immediately and releases
117
+ * Resolves `{ ready: true, ... }` when the iframe posts
118
+ * `blink:iframe-ready` (with `fluidCapable` reflecting its advertised
119
+ * capabilities), or `{ ready: false, fluidCapable: false }` on timeout.
120
+ * `cancel()` settles the promise as not-ready immediately and releases
102
121
  * the listener + timer — used to reap the generous warm-up wait once it no
103
122
  * longer matters (warm iframe consumed or discarded).
104
123
  */
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
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';
1
+ import { D as DepositStatus, a as DepositResult, b as DepositError, c as DepositConfig, d as DepositRequest } from './types-iQf3f-_m.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-iQf3f-_m.js';
3
3
 
4
4
  declare const DEFAULT_WEBVIEW_BASE_URL = "https://pay.blink.cash";
5
5
  declare const SANDBOX_WEBVIEW_BASE_URL = "https://pay-sandbox.blink.cash";
@@ -94,11 +94,30 @@ declare class Deposit {
94
94
  * config, so the full widget renders only when both allow it.
95
95
  */
96
96
  private applyFullWidgetParam;
97
+ /** Fluid is the default; `layout: 'fixed'` opts back into the legacy container. */
98
+ private isFluidLayout;
99
+ /**
100
+ * Marks the hosted-flow URL as fluid-layout: the iframe spans the full
101
+ * viewport and the hosted flow renders the card/sheet chrome itself.
102
+ * Only applied to preload URLs — the URL-param fallback path exists
103
+ * precisely because the webview never signalled ready, so it cannot be
104
+ * assumed to understand fluid layout and gets the fixed container.
105
+ */
106
+ private applyLayoutParam;
107
+ /**
108
+ * Seeds the merchant page's large-viewport height and safe-area bottom
109
+ * inset onto the fluid preload URL so the hosted flow can size the sheet
110
+ * before its JS boots. `blink:viewport` messages keep the values fresh
111
+ * afterwards (rotation, window resize) — see iframe.ts.
112
+ */
113
+ private applyViewportParams;
97
114
  private setStatus;
98
115
  private runSignerFlow;
99
116
  /**
100
- * Resolves true when the iframe posts `blink:iframe-ready`, false on
101
- * timeout. `cancel()` settles the promise as false immediately and releases
117
+ * Resolves `{ ready: true, ... }` when the iframe posts
118
+ * `blink:iframe-ready` (with `fluidCapable` reflecting its advertised
119
+ * capabilities), or `{ ready: false, fluidCapable: false }` on timeout.
120
+ * `cancel()` settles the promise as not-ready immediately and releases
102
121
  * the listener + timer — used to reap the generous warm-up wait once it no
103
122
  * longer matters (warm iframe consumed or discarded).
104
123
  */
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, SANDBOX_WEBVIEW_BASE_URL, attachRpcHost, createWalletDiscoverer, getDisplayMessage, parseBridgeMessage } from './chunk-VMXCXXVN.js';
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-NZ7DOPZ5.js';
2
2
 
3
3
  // src/index.ts
4
4
  var VERSION = "0.3.0";
package/dist/react.cjs CHANGED
@@ -101,7 +101,19 @@ function parseIframeReady(data) {
101
101
  if (msg.type !== "blink:iframe-ready") {
102
102
  return null;
103
103
  }
104
- return { type: "blink:iframe-ready" };
104
+ return { type: "blink:iframe-ready", capabilities: parseCapabilities(msg.capabilities) };
105
+ }
106
+ function parseCapabilities(value) {
107
+ if (!Array.isArray(value)) {
108
+ return [];
109
+ }
110
+ return value.filter((entry) => typeof entry === "string");
111
+ }
112
+ function buildViewportMessage(viewportLvh, safeAreaBottom) {
113
+ return { type: "blink:viewport", viewportLvh, safeAreaBottom };
114
+ }
115
+ function buildRevealMessage() {
116
+ return { type: "blink:reveal" };
105
117
  }
106
118
  function buildSignedPayloadMessage(merchantId, payload, signature) {
107
119
  return {
@@ -508,6 +520,34 @@ function normalizeProviderError(err) {
508
520
  return { code: -32603, message: typeof err === "string" ? err : "Provider error" };
509
521
  }
510
522
 
523
+ // src/viewportMetrics.ts
524
+ function measureViewportMetrics() {
525
+ const unavailable = { viewportLvh: 0, safeAreaBottom: 0 };
526
+ if (typeof document === "undefined" || typeof window === "undefined" || typeof window.getComputedStyle !== "function" || !document.body) {
527
+ return unavailable;
528
+ }
529
+ try {
530
+ const probe = document.createElement("div");
531
+ probe.style.cssText = "position:fixed;top:0;left:0;width:0;visibility:hidden;pointer-events:none;height:100lvh;padding-bottom:env(safe-area-inset-bottom,0px)";
532
+ document.body.appendChild(probe);
533
+ let viewportLvh = 0;
534
+ let safeAreaBottom = 0;
535
+ try {
536
+ const computed = window.getComputedStyle(probe);
537
+ viewportLvh = Math.round(Number.parseFloat(computed.height) || 0);
538
+ safeAreaBottom = Math.round(Number.parseFloat(computed.paddingBottom) || 0);
539
+ } finally {
540
+ probe.remove();
541
+ }
542
+ if (viewportLvh <= 0) {
543
+ viewportLvh = Math.round(window.innerHeight || 0);
544
+ }
545
+ return { viewportLvh, safeAreaBottom };
546
+ } catch {
547
+ return unavailable;
548
+ }
549
+ }
550
+
511
551
  // src/iframe.ts
512
552
  var STYLE_ID = "blink-deposit-styles";
513
553
  var CLOSE_DURATION_MS = 280;
@@ -528,6 +568,8 @@ var STYLES = `
528
568
  [data-blink-overlay][data-blink-mobile-sheet] [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)}
529
569
  [data-blink-overlay][data-blink-mobile-sheet][data-blink-closing] [data-blink-container]{opacity:1;animation:blink-slide-down-full ${CLOSE_DURATION_MS}ms ease-in forwards}
530
570
  @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}}
571
+ [data-blink-overlay][data-blink-fluid] [data-blink-container],[data-blink-overlay][data-blink-fluid][data-blink-mobile-sheet] [data-blink-container]{width:100%;max-width:100%;height:100%;max-height:100%;border-radius:0;box-shadow:none;animation:none;background:transparent;padding-bottom:0}
572
+ [data-blink-overlay][data-blink-fluid][data-blink-closing] [data-blink-container]{animation:none;transition:none;opacity:1}
531
573
  `;
532
574
  function createIframe(url, containerElement, options) {
533
575
  ensureStyles();
@@ -539,6 +581,9 @@ function createIframe(url, containerElement, options) {
539
581
  if (shouldUseMobileSheetLayout()) {
540
582
  overlay.setAttribute("data-blink-mobile-sheet", "");
541
583
  }
584
+ if (options?.fluid) {
585
+ overlay.setAttribute("data-blink-fluid", "");
586
+ }
542
587
  if (hidden) {
543
588
  overlay.style.display = "none";
544
589
  }
@@ -567,6 +612,37 @@ function createIframe(url, containerElement, options) {
567
612
  };
568
613
  attachBridge();
569
614
  iframe.addEventListener("load", attachBridge);
615
+ function postReveal() {
616
+ if (closed) return;
617
+ iframe.contentWindow?.postMessage(buildRevealMessage(), iframeOrigin);
618
+ }
619
+ function postViewportMetrics() {
620
+ if (closed || !options?.fluid) return;
621
+ const metrics = measureViewportMetrics();
622
+ if (metrics.viewportLvh <= 0) return;
623
+ iframe.contentWindow?.postMessage(
624
+ buildViewportMessage(metrics.viewportLvh, metrics.safeAreaBottom),
625
+ iframeOrigin
626
+ );
627
+ }
628
+ let viewportPostScheduled = false;
629
+ const onViewportChange = () => {
630
+ if (viewportPostScheduled) return;
631
+ viewportPostScheduled = true;
632
+ requestAnimationFrame(() => {
633
+ viewportPostScheduled = false;
634
+ postViewportMetrics();
635
+ });
636
+ };
637
+ if (options?.fluid) {
638
+ window.addEventListener("resize", onViewportChange);
639
+ window.addEventListener("orientationchange", onViewportChange);
640
+ }
641
+ const onLoadReveal = () => {
642
+ postViewportMetrics();
643
+ if (!hidden) postReveal();
644
+ };
645
+ iframe.addEventListener("load", onLoadReveal);
570
646
  let savedOverflow = "";
571
647
  let scrollLocked = false;
572
648
  const onBackdropClick = (event) => {
@@ -597,6 +673,8 @@ function createIframe(url, containerElement, options) {
597
673
  overlay.removeEventListener("click", onBackdropClick);
598
674
  overlay.removeEventListener("touchmove", onTouchMove);
599
675
  document.removeEventListener("keydown", onKeyDown);
676
+ window.removeEventListener("resize", onViewportChange);
677
+ window.removeEventListener("orientationchange", onViewportChange);
600
678
  }
601
679
  function unlockScroll() {
602
680
  if (!scrollLocked) return;
@@ -622,6 +700,7 @@ function createIframe(url, containerElement, options) {
622
700
  }
623
701
  function detachBridge() {
624
702
  iframe.removeEventListener("load", attachBridge);
703
+ iframe.removeEventListener("load", onLoadReveal);
625
704
  if (rpcHostHandle) {
626
705
  rpcHostHandle.detach();
627
706
  rpcHostHandle = null;
@@ -652,6 +731,14 @@ function createIframe(url, containerElement, options) {
652
731
  overlay.style.display = "";
653
732
  lockScroll();
654
733
  attachDismissalListeners();
734
+ postViewportMetrics();
735
+ postReveal();
736
+ },
737
+ postReveal() {
738
+ postReveal();
739
+ },
740
+ downgradeToFixed() {
741
+ overlay.removeAttribute("data-blink-fluid");
655
742
  },
656
743
  onClose(callback) {
657
744
  closeCallback = callback;
@@ -827,6 +914,8 @@ var DEFAULT_WEBVIEW_BASE_URL = "https://pay.blink.cash";
827
914
  var SANDBOX_WEBVIEW_BASE_URL = "https://pay-sandbox.blink.cash";
828
915
  var IFRAME_READY_TIMEOUT_MS = 2e3;
829
916
  var WARM_IFRAME_READY_TIMEOUT_MS = 6e4;
917
+ var LAYOUT_FLUID_CAPABILITY = "layout-fluid";
918
+ var IFRAME_NOT_READY = { ready: false, fluidCapable: false };
830
919
  function resolveWebviewBaseUrl(config) {
831
920
  if (config.webviewBaseUrl) return config.webviewBaseUrl;
832
921
  return config.environment === "sandbox" ? SANDBOX_WEBVIEW_BASE_URL : DEFAULT_WEBVIEW_BASE_URL;
@@ -897,7 +986,10 @@ var Deposit = class {
897
986
  const webviewBaseUrl = resolveWebviewBaseUrl(this.config);
898
987
  this.hostedOrigin = this.config.hostedFlowOrigin ?? new URL(webviewBaseUrl).origin;
899
988
  const preloadUrl = this.buildPreloadUrl(webviewBaseUrl);
900
- const iframe = createIframe(preloadUrl, this.config.containerElement, { hidden: true });
989
+ const iframe = createIframe(preloadUrl, this.config.containerElement, {
990
+ hidden: true,
991
+ fluid: this.isFluidLayout()
992
+ });
901
993
  const ready = this.waitForIframeReady(iframe, WARM_IFRAME_READY_TIMEOUT_MS);
902
994
  this.warmIframe = iframe;
903
995
  this.warmIframeReady = ready.promise;
@@ -933,6 +1025,8 @@ var Deposit = class {
933
1025
  preloadUrl.searchParams.set("merchantId", this.config.merchantId);
934
1026
  }
935
1027
  this.applyFullWidgetParam(preloadUrl);
1028
+ this.applyLayoutParam(preloadUrl);
1029
+ this.applyViewportParams(preloadUrl);
936
1030
  return preloadUrl.toString();
937
1031
  }
938
1032
  /**
@@ -1078,6 +1172,35 @@ var Deposit = class {
1078
1172
  url.searchParams.set("enableFullWidget", "false");
1079
1173
  }
1080
1174
  }
1175
+ /** Fluid is the default; `layout: 'fixed'` opts back into the legacy container. */
1176
+ isFluidLayout() {
1177
+ return this.config.layout !== "fixed";
1178
+ }
1179
+ /**
1180
+ * Marks the hosted-flow URL as fluid-layout: the iframe spans the full
1181
+ * viewport and the hosted flow renders the card/sheet chrome itself.
1182
+ * Only applied to preload URLs — the URL-param fallback path exists
1183
+ * precisely because the webview never signalled ready, so it cannot be
1184
+ * assumed to understand fluid layout and gets the fixed container.
1185
+ */
1186
+ applyLayoutParam(url) {
1187
+ if (this.isFluidLayout()) {
1188
+ url.searchParams.set("layout", "fluid");
1189
+ }
1190
+ }
1191
+ /**
1192
+ * Seeds the merchant page's large-viewport height and safe-area bottom
1193
+ * inset onto the fluid preload URL so the hosted flow can size the sheet
1194
+ * before its JS boots. `blink:viewport` messages keep the values fresh
1195
+ * afterwards (rotation, window resize) — see iframe.ts.
1196
+ */
1197
+ applyViewportParams(url) {
1198
+ if (!this.isFluidLayout()) return;
1199
+ const metrics = measureViewportMetrics();
1200
+ if (metrics.viewportLvh <= 0) return;
1201
+ url.searchParams.set("viewportLvh", String(metrics.viewportLvh));
1202
+ url.searchParams.set("safeAreaBottom", String(metrics.safeAreaBottom));
1203
+ }
1081
1204
  setStatus(status) {
1082
1205
  if (this._status === status) return;
1083
1206
  this.log(`Status: ${this._status} \u2192 ${status}`);
@@ -1101,7 +1224,7 @@ var Deposit = class {
1101
1224
  iframeReadyPromise = Promise.race([
1102
1225
  warm.ready,
1103
1226
  new Promise(
1104
- (resolve) => setTimeout(() => resolve(false), IFRAME_READY_TIMEOUT_MS)
1227
+ (resolve) => setTimeout(() => resolve(IFRAME_NOT_READY), IFRAME_READY_TIMEOUT_MS)
1105
1228
  )
1106
1229
  ]).then((ready) => {
1107
1230
  warm.cancelReady();
@@ -1111,7 +1234,8 @@ var Deposit = class {
1111
1234
  } else {
1112
1235
  preloadIframe = createIframe(
1113
1236
  this.buildPreloadUrl(webviewBaseUrl),
1114
- this.config.containerElement
1237
+ this.config.containerElement,
1238
+ { fluid: this.isFluidLayout() }
1115
1239
  );
1116
1240
  iframeReadyPromise = this.waitForIframeReady(preloadIframe).promise;
1117
1241
  }
@@ -1141,7 +1265,11 @@ var Deposit = class {
1141
1265
  this.log("Request superseded or iframe dismissed during signer call");
1142
1266
  return;
1143
1267
  }
1144
- if (iframeReady) {
1268
+ if (iframeReady.ready) {
1269
+ if (this.isFluidLayout() && !iframeReady.fluidCapable) {
1270
+ preloadIframe.downgradeToFixed();
1271
+ this.log("Webview lacks layout-fluid capability \u2014 downgraded to fixed container");
1272
+ }
1145
1273
  const contentWindow = preloadIframe.contentWindow;
1146
1274
  if (contentWindow) {
1147
1275
  contentWindow.postMessage(
@@ -1196,8 +1324,10 @@ var Deposit = class {
1196
1324
  }
1197
1325
  }
1198
1326
  /**
1199
- * Resolves true when the iframe posts `blink:iframe-ready`, false on
1200
- * timeout. `cancel()` settles the promise as false immediately and releases
1327
+ * Resolves `{ ready: true, ... }` when the iframe posts
1328
+ * `blink:iframe-ready` (with `fluidCapable` reflecting its advertised
1329
+ * capabilities), or `{ ready: false, fluidCapable: false }` on timeout.
1330
+ * `cancel()` settles the promise as not-ready immediately and releases
1201
1331
  * the listener + timer — used to reap the generous warm-up wait once it no
1202
1332
  * longer matters (warm iframe consumed or discarded).
1203
1333
  */
@@ -1208,25 +1338,29 @@ var Deposit = class {
1208
1338
  const handler = (event) => {
1209
1339
  if (event.origin !== this.hostedOrigin) return;
1210
1340
  if (event.source !== iframeHandle.contentWindow) return;
1211
- if (parseIframeReady(event.data)) {
1212
- finish(true);
1341
+ const readyMessage = parseIframeReady(event.data);
1342
+ if (readyMessage) {
1343
+ finish({
1344
+ ready: true,
1345
+ fluidCapable: readyMessage.capabilities.includes(LAYOUT_FLUID_CAPABILITY)
1346
+ });
1213
1347
  }
1214
1348
  };
1215
1349
  window.addEventListener("message", handler);
1216
1350
  const timeout = setTimeout(() => {
1217
1351
  this.log("Iframe ready timeout \u2014 falling back to URL params");
1218
- finish(false);
1352
+ finish(IFRAME_NOT_READY);
1219
1353
  }, timeoutMs);
1220
1354
  let settled = false;
1221
- finish = (ready) => {
1355
+ finish = (result) => {
1222
1356
  if (settled) return;
1223
1357
  settled = true;
1224
1358
  window.removeEventListener("message", handler);
1225
1359
  clearTimeout(timeout);
1226
- resolve(ready);
1360
+ resolve(result);
1227
1361
  };
1228
1362
  });
1229
- return { promise, cancel: () => finish(false) };
1363
+ return { promise, cancel: () => finish(IFRAME_NOT_READY) };
1230
1364
  }
1231
1365
  startMessageListener(iframeHandle, onComplete) {
1232
1366
  const handler = (event) => {