@swype-org/deposit 0.3.20 → 0.3.23

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-JD7GTL6D.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 {
@@ -325,13 +337,20 @@ function attachRpcHost(options) {
325
337
  });
326
338
  }
327
339
  }
328
- function advertiseWallets(snapshot) {
340
+ let lastAdvertisedKey = null;
341
+ function advertiseWallets(snapshot, opts) {
329
342
  const wallets = snapshot.map((entry) => ({
330
343
  uuid: entry.info.uuid,
331
344
  rdns: entry.info.rdns,
332
345
  name: entry.info.name,
333
346
  icon: entry.info.icon
334
347
  }));
348
+ const key = JSON.stringify(wallets.map((w) => [w.uuid, w.rdns, w.name, w.icon]));
349
+ if (!opts?.force && key === lastAdvertisedKey) {
350
+ log("skipping identical re-advertisement", { count: wallets.length });
351
+ return;
352
+ }
353
+ lastAdvertisedKey = key;
335
354
  console.info("[blink-bridge:parent] advertising wallets", wallets.map((w) => ({
336
355
  rdns: w.rdns,
337
356
  name: w.name
@@ -412,7 +431,7 @@ function attachRpcHost(options) {
412
431
  if (!message) return;
413
432
  switch (message.type) {
414
433
  case "blink:bridge-hello": {
415
- advertiseWallets(discoverer.list());
434
+ advertiseWallets(discoverer.list(), { force: true });
416
435
  discoverer.requestProviders();
417
436
  return;
418
437
  }
@@ -508,6 +527,34 @@ function normalizeProviderError(err) {
508
527
  return { code: -32603, message: typeof err === "string" ? err : "Provider error" };
509
528
  }
510
529
 
530
+ // src/viewportMetrics.ts
531
+ function measureViewportMetrics() {
532
+ const unavailable = { viewportLvh: 0, safeAreaBottom: 0 };
533
+ if (typeof document === "undefined" || typeof window === "undefined" || typeof window.getComputedStyle !== "function" || !document.body) {
534
+ return unavailable;
535
+ }
536
+ try {
537
+ const probe = document.createElement("div");
538
+ 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)";
539
+ document.body.appendChild(probe);
540
+ let viewportLvh = 0;
541
+ let safeAreaBottom = 0;
542
+ try {
543
+ const computed = window.getComputedStyle(probe);
544
+ viewportLvh = Math.round(Number.parseFloat(computed.height) || 0);
545
+ safeAreaBottom = Math.round(Number.parseFloat(computed.paddingBottom) || 0);
546
+ } finally {
547
+ probe.remove();
548
+ }
549
+ if (viewportLvh <= 0) {
550
+ viewportLvh = Math.round(window.innerHeight || 0);
551
+ }
552
+ return { viewportLvh, safeAreaBottom };
553
+ } catch {
554
+ return unavailable;
555
+ }
556
+ }
557
+
511
558
  // src/iframe.ts
512
559
  var STYLE_ID = "blink-deposit-styles";
513
560
  var CLOSE_DURATION_MS = 280;
@@ -528,6 +575,8 @@ var STYLES = `
528
575
  [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
576
  [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
577
  @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}}
578
+ [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}
579
+ [data-blink-overlay][data-blink-fluid][data-blink-closing] [data-blink-container]{animation:none;transition:none;opacity:1}
531
580
  `;
532
581
  function createIframe(url, containerElement, options) {
533
582
  ensureStyles();
@@ -539,6 +588,9 @@ function createIframe(url, containerElement, options) {
539
588
  if (shouldUseMobileSheetLayout()) {
540
589
  overlay.setAttribute("data-blink-mobile-sheet", "");
541
590
  }
591
+ if (options?.fluid) {
592
+ overlay.setAttribute("data-blink-fluid", "");
593
+ }
542
594
  if (hidden) {
543
595
  overlay.style.display = "none";
544
596
  }
@@ -567,6 +619,37 @@ function createIframe(url, containerElement, options) {
567
619
  };
568
620
  attachBridge();
569
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);
570
653
  let savedOverflow = "";
571
654
  let scrollLocked = false;
572
655
  const onBackdropClick = (event) => {
@@ -597,6 +680,8 @@ function createIframe(url, containerElement, options) {
597
680
  overlay.removeEventListener("click", onBackdropClick);
598
681
  overlay.removeEventListener("touchmove", onTouchMove);
599
682
  document.removeEventListener("keydown", onKeyDown);
683
+ window.removeEventListener("resize", onViewportChange);
684
+ window.removeEventListener("orientationchange", onViewportChange);
600
685
  }
601
686
  function unlockScroll() {
602
687
  if (!scrollLocked) return;
@@ -622,6 +707,7 @@ function createIframe(url, containerElement, options) {
622
707
  }
623
708
  function detachBridge() {
624
709
  iframe.removeEventListener("load", attachBridge);
710
+ iframe.removeEventListener("load", onLoadReveal);
625
711
  if (rpcHostHandle) {
626
712
  rpcHostHandle.detach();
627
713
  rpcHostHandle = null;
@@ -652,6 +738,14 @@ function createIframe(url, containerElement, options) {
652
738
  overlay.style.display = "";
653
739
  lockScroll();
654
740
  attachDismissalListeners();
741
+ postViewportMetrics();
742
+ postReveal();
743
+ },
744
+ postReveal() {
745
+ postReveal();
746
+ },
747
+ downgradeToFixed() {
748
+ overlay.removeAttribute("data-blink-fluid");
655
749
  },
656
750
  onClose(callback) {
657
751
  closeCallback = callback;
@@ -827,6 +921,8 @@ var DEFAULT_WEBVIEW_BASE_URL = "https://pay.blink.cash";
827
921
  var SANDBOX_WEBVIEW_BASE_URL = "https://pay-sandbox.blink.cash";
828
922
  var IFRAME_READY_TIMEOUT_MS = 2e3;
829
923
  var WARM_IFRAME_READY_TIMEOUT_MS = 6e4;
924
+ var LAYOUT_FLUID_CAPABILITY = "layout-fluid";
925
+ var IFRAME_NOT_READY = { ready: false, fluidCapable: false };
830
926
  function resolveWebviewBaseUrl(config) {
831
927
  if (config.webviewBaseUrl) return config.webviewBaseUrl;
832
928
  return config.environment === "sandbox" ? SANDBOX_WEBVIEW_BASE_URL : DEFAULT_WEBVIEW_BASE_URL;
@@ -897,7 +993,10 @@ var Deposit = class {
897
993
  const webviewBaseUrl = resolveWebviewBaseUrl(this.config);
898
994
  this.hostedOrigin = this.config.hostedFlowOrigin ?? new URL(webviewBaseUrl).origin;
899
995
  const preloadUrl = this.buildPreloadUrl(webviewBaseUrl);
900
- const iframe = createIframe(preloadUrl, this.config.containerElement, { hidden: true });
996
+ const iframe = createIframe(preloadUrl, this.config.containerElement, {
997
+ hidden: true,
998
+ fluid: this.isFluidLayout()
999
+ });
901
1000
  const ready = this.waitForIframeReady(iframe, WARM_IFRAME_READY_TIMEOUT_MS);
902
1001
  this.warmIframe = iframe;
903
1002
  this.warmIframeReady = ready.promise;
@@ -933,6 +1032,8 @@ var Deposit = class {
933
1032
  preloadUrl.searchParams.set("merchantId", this.config.merchantId);
934
1033
  }
935
1034
  this.applyFullWidgetParam(preloadUrl);
1035
+ this.applyLayoutParam(preloadUrl);
1036
+ this.applyViewportParams(preloadUrl);
936
1037
  return preloadUrl.toString();
937
1038
  }
938
1039
  /**
@@ -1078,6 +1179,35 @@ var Deposit = class {
1078
1179
  url.searchParams.set("enableFullWidget", "false");
1079
1180
  }
1080
1181
  }
1182
+ /** Fluid is the default; `layout: 'fixed'` opts back into the legacy container. */
1183
+ isFluidLayout() {
1184
+ return this.config.layout !== "fixed";
1185
+ }
1186
+ /**
1187
+ * Marks the hosted-flow URL as fluid-layout: the iframe spans the full
1188
+ * viewport and the hosted flow renders the card/sheet chrome itself.
1189
+ * Only applied to preload URLs — the URL-param fallback path exists
1190
+ * precisely because the webview never signalled ready, so it cannot be
1191
+ * assumed to understand fluid layout and gets the fixed container.
1192
+ */
1193
+ applyLayoutParam(url) {
1194
+ if (this.isFluidLayout()) {
1195
+ url.searchParams.set("layout", "fluid");
1196
+ }
1197
+ }
1198
+ /**
1199
+ * Seeds the merchant page's large-viewport height and safe-area bottom
1200
+ * inset onto the fluid preload URL so the hosted flow can size the sheet
1201
+ * before its JS boots. `blink:viewport` messages keep the values fresh
1202
+ * afterwards (rotation, window resize) — see iframe.ts.
1203
+ */
1204
+ applyViewportParams(url) {
1205
+ if (!this.isFluidLayout()) return;
1206
+ const metrics = measureViewportMetrics();
1207
+ if (metrics.viewportLvh <= 0) return;
1208
+ url.searchParams.set("viewportLvh", String(metrics.viewportLvh));
1209
+ url.searchParams.set("safeAreaBottom", String(metrics.safeAreaBottom));
1210
+ }
1081
1211
  setStatus(status) {
1082
1212
  if (this._status === status) return;
1083
1213
  this.log(`Status: ${this._status} \u2192 ${status}`);
@@ -1101,7 +1231,7 @@ var Deposit = class {
1101
1231
  iframeReadyPromise = Promise.race([
1102
1232
  warm.ready,
1103
1233
  new Promise(
1104
- (resolve) => setTimeout(() => resolve(false), IFRAME_READY_TIMEOUT_MS)
1234
+ (resolve) => setTimeout(() => resolve(IFRAME_NOT_READY), IFRAME_READY_TIMEOUT_MS)
1105
1235
  )
1106
1236
  ]).then((ready) => {
1107
1237
  warm.cancelReady();
@@ -1111,7 +1241,8 @@ var Deposit = class {
1111
1241
  } else {
1112
1242
  preloadIframe = createIframe(
1113
1243
  this.buildPreloadUrl(webviewBaseUrl),
1114
- this.config.containerElement
1244
+ this.config.containerElement,
1245
+ { fluid: this.isFluidLayout() }
1115
1246
  );
1116
1247
  iframeReadyPromise = this.waitForIframeReady(preloadIframe).promise;
1117
1248
  }
@@ -1141,7 +1272,11 @@ var Deposit = class {
1141
1272
  this.log("Request superseded or iframe dismissed during signer call");
1142
1273
  return;
1143
1274
  }
1144
- if (iframeReady) {
1275
+ if (iframeReady.ready) {
1276
+ if (this.isFluidLayout() && !iframeReady.fluidCapable) {
1277
+ preloadIframe.downgradeToFixed();
1278
+ this.log("Webview lacks layout-fluid capability \u2014 downgraded to fixed container");
1279
+ }
1145
1280
  const contentWindow = preloadIframe.contentWindow;
1146
1281
  if (contentWindow) {
1147
1282
  contentWindow.postMessage(
@@ -1196,8 +1331,10 @@ var Deposit = class {
1196
1331
  }
1197
1332
  }
1198
1333
  /**
1199
- * Resolves true when the iframe posts `blink:iframe-ready`, false on
1200
- * timeout. `cancel()` settles the promise as false immediately and releases
1334
+ * Resolves `{ ready: true, ... }` when the iframe posts
1335
+ * `blink:iframe-ready` (with `fluidCapable` reflecting its advertised
1336
+ * capabilities), or `{ ready: false, fluidCapable: false }` on timeout.
1337
+ * `cancel()` settles the promise as not-ready immediately and releases
1201
1338
  * the listener + timer — used to reap the generous warm-up wait once it no
1202
1339
  * longer matters (warm iframe consumed or discarded).
1203
1340
  */
@@ -1208,25 +1345,29 @@ var Deposit = class {
1208
1345
  const handler = (event) => {
1209
1346
  if (event.origin !== this.hostedOrigin) return;
1210
1347
  if (event.source !== iframeHandle.contentWindow) return;
1211
- if (parseIframeReady(event.data)) {
1212
- finish(true);
1348
+ const readyMessage = parseIframeReady(event.data);
1349
+ if (readyMessage) {
1350
+ finish({
1351
+ ready: true,
1352
+ fluidCapable: readyMessage.capabilities.includes(LAYOUT_FLUID_CAPABILITY)
1353
+ });
1213
1354
  }
1214
1355
  };
1215
1356
  window.addEventListener("message", handler);
1216
1357
  const timeout = setTimeout(() => {
1217
1358
  this.log("Iframe ready timeout \u2014 falling back to URL params");
1218
- finish(false);
1359
+ finish(IFRAME_NOT_READY);
1219
1360
  }, timeoutMs);
1220
1361
  let settled = false;
1221
- finish = (ready) => {
1362
+ finish = (result) => {
1222
1363
  if (settled) return;
1223
1364
  settled = true;
1224
1365
  window.removeEventListener("message", handler);
1225
1366
  clearTimeout(timeout);
1226
- resolve(ready);
1367
+ resolve(result);
1227
1368
  };
1228
1369
  });
1229
- return { promise, cancel: () => finish(false) };
1370
+ return { promise, cancel: () => finish(IFRAME_NOT_READY) };
1230
1371
  }
1231
1372
  startMessageListener(iframeHandle, onComplete) {
1232
1373
  const handler = (event) => {