@metamask/connect-multichain 0.5.3 → 0.7.0

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.
Files changed (60) hide show
  1. package/CHANGELOG.md +41 -1
  2. package/README.md +30 -22
  3. package/dist/browser/es/connect-multichain.d.mts +29 -4
  4. package/dist/browser/es/connect-multichain.mjs +636 -335
  5. package/dist/browser/es/connect-multichain.mjs.map +1 -1
  6. package/dist/browser/es/metafile-esm.json +1 -1
  7. package/dist/browser/iife/connect-multichain.d.ts +29 -4
  8. package/dist/browser/iife/connect-multichain.js +3487 -3072
  9. package/dist/browser/iife/connect-multichain.js.map +1 -1
  10. package/dist/browser/iife/metafile-iife.json +1 -1
  11. package/dist/browser/umd/connect-multichain.d.ts +29 -4
  12. package/dist/browser/umd/connect-multichain.js +636 -335
  13. package/dist/browser/umd/connect-multichain.js.map +1 -1
  14. package/dist/browser/umd/metafile-cjs.json +1 -1
  15. package/dist/node/cjs/connect-multichain.d.ts +29 -4
  16. package/dist/node/cjs/connect-multichain.js +454 -153
  17. package/dist/node/cjs/connect-multichain.js.map +1 -1
  18. package/dist/node/cjs/metafile-cjs.json +1 -1
  19. package/dist/node/es/connect-multichain.d.mts +29 -4
  20. package/dist/node/es/connect-multichain.mjs +454 -153
  21. package/dist/node/es/connect-multichain.mjs.map +1 -1
  22. package/dist/node/es/metafile-esm.json +1 -1
  23. package/dist/react-native/es/connect-multichain.d.mts +29 -4
  24. package/dist/react-native/es/connect-multichain.mjs +629 -328
  25. package/dist/react-native/es/connect-multichain.mjs.map +1 -1
  26. package/dist/react-native/es/metafile-esm.json +1 -1
  27. package/dist/src/domain/multichain/index.d.ts +15 -4
  28. package/dist/src/domain/multichain/index.d.ts.map +1 -1
  29. package/dist/src/domain/multichain/index.js +14 -0
  30. package/dist/src/domain/multichain/index.js.map +1 -1
  31. package/dist/src/domain/multichain/types.d.ts +14 -0
  32. package/dist/src/domain/multichain/types.d.ts.map +1 -1
  33. package/dist/src/multichain/index.d.ts +3 -2
  34. package/dist/src/multichain/index.d.ts.map +1 -1
  35. package/dist/src/multichain/index.js +158 -61
  36. package/dist/src/multichain/index.js.map +1 -1
  37. package/dist/src/multichain/transports/default/index.d.ts +3 -1
  38. package/dist/src/multichain/transports/default/index.d.ts.map +1 -1
  39. package/dist/src/multichain/transports/default/index.js +17 -11
  40. package/dist/src/multichain/transports/default/index.js.map +1 -1
  41. package/dist/src/multichain/transports/multichainApiClientWrapper/index.d.ts +3 -1
  42. package/dist/src/multichain/transports/multichainApiClientWrapper/index.d.ts.map +1 -1
  43. package/dist/src/multichain/transports/multichainApiClientWrapper/index.js +28 -32
  44. package/dist/src/multichain/transports/multichainApiClientWrapper/index.js.map +1 -1
  45. package/dist/src/multichain/transports/mwp/index.d.ts +15 -2
  46. package/dist/src/multichain/transports/mwp/index.d.ts.map +1 -1
  47. package/dist/src/multichain/transports/mwp/index.js +161 -39
  48. package/dist/src/multichain/transports/mwp/index.js.map +1 -1
  49. package/dist/src/multichain/utils/index.d.ts +23 -0
  50. package/dist/src/multichain/utils/index.d.ts.map +1 -1
  51. package/dist/src/multichain/utils/index.js +94 -4
  52. package/dist/src/multichain/utils/index.js.map +1 -1
  53. package/dist/src/polyfills/buffer-shim.js +4 -14
  54. package/dist/src/polyfills/buffer-shim.js.map +1 -1
  55. package/dist/src/store/adapters/web.d.ts +1 -1
  56. package/dist/src/store/adapters/web.d.ts.map +1 -1
  57. package/dist/src/store/adapters/web.js +1 -1
  58. package/dist/src/store/adapters/web.js.map +1 -1
  59. package/dist/types/connect-multichain.d.ts +29 -4
  60. package/package.json +2 -2
@@ -55,14 +55,6 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
55
55
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
56
56
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
57
57
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
58
- var __privateWrapper = (obj, member, setter, getter) => ({
59
- set _(value) {
60
- __privateSet(obj, member, value, setter);
61
- },
62
- get _() {
63
- return __privateGet(obj, member, getter);
64
- }
65
- });
66
58
  var __async = (__this, __arguments, generator) => {
67
59
  return new Promise((resolve, reject) => {
68
60
  var fulfilled = (value) => {
@@ -428,6 +420,34 @@ var init_multichain = __esm({
428
420
  super();
429
421
  this.options = options;
430
422
  }
423
+ /**
424
+ * Merges the given options into the current instance options.
425
+ * Only the mergeable keys are updated (api.supportedNetworks, ui.*, mobile.*, transport.extensionId, debug).
426
+ * The main thing to note is that the value for `dapp` is not merged as it does not make sense for
427
+ * subsequent calls to `createMultichainClient` to have a different `dapp` value.
428
+ * Used when createMultichainClient is called with an existing singleton.
429
+ *
430
+ * @param partial - Options to merge/overwrite onto the current instance
431
+ */
432
+ mergeOptions(partial) {
433
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
434
+ const opts = this.options;
435
+ this.options = __spreadProps(__spreadValues({}, opts), {
436
+ api: __spreadProps(__spreadValues({}, opts.api), {
437
+ supportedNetworks: __spreadValues(__spreadValues({}, opts.api.supportedNetworks), (_b = (_a2 = partial.api) == null ? void 0 : _a2.supportedNetworks) != null ? _b : {})
438
+ }),
439
+ ui: __spreadProps(__spreadValues({}, opts.ui), {
440
+ headless: (_d = (_c = partial.ui) == null ? void 0 : _c.headless) != null ? _d : opts.ui.headless,
441
+ preferExtension: (_f = (_e = partial.ui) == null ? void 0 : _e.preferExtension) != null ? _f : opts.ui.preferExtension,
442
+ showInstallModal: (_h = (_g = partial.ui) == null ? void 0 : _g.showInstallModal) != null ? _h : opts.ui.showInstallModal
443
+ }),
444
+ mobile: __spreadValues(__spreadValues({}, opts.mobile), (_i = partial.mobile) != null ? _i : {}),
445
+ transport: __spreadProps(__spreadValues({}, (_j = opts.transport) != null ? _j : {}), {
446
+ extensionId: (_m = (_k = partial.transport) == null ? void 0 : _k.extensionId) != null ? _m : (_l = opts.transport) == null ? void 0 : _l.extensionId
447
+ }),
448
+ debug: (_n = partial.debug) != null ? _n : opts.debug
449
+ });
450
+ }
431
451
  };
432
452
  }
433
453
  });
@@ -613,6 +633,21 @@ var init_ui = __esm({
613
633
  });
614
634
 
615
635
  // src/multichain/utils/index.ts
636
+ function getGlobalObject() {
637
+ if (typeof globalThis !== "undefined") {
638
+ return globalThis;
639
+ }
640
+ if (typeof global !== "undefined") {
641
+ return global;
642
+ }
643
+ if (typeof self !== "undefined") {
644
+ return self;
645
+ }
646
+ if (typeof window !== "undefined") {
647
+ return window;
648
+ }
649
+ throw new Error("Unable to locate global object");
650
+ }
616
651
  function base64Encode(str) {
617
652
  if (typeof btoa !== "undefined") {
618
653
  return btoa(str);
@@ -646,6 +681,29 @@ function openDeeplink(options, deeplink, universalLink) {
646
681
  link.click();
647
682
  }
648
683
  }
684
+ function mergeRequestedSessionWithExisting(sessionData, scopes, caipAccountIds, sessionProperties) {
685
+ const existingCaipChainIds = Object.keys(sessionData.sessionScopes);
686
+ const existingCaipAccountIds = [];
687
+ Object.values(sessionData.sessionScopes).forEach((scopeObject) => {
688
+ if ((scopeObject == null ? void 0 : scopeObject.accounts) && Array.isArray(scopeObject.accounts)) {
689
+ scopeObject.accounts.forEach((account) => {
690
+ existingCaipAccountIds.push(account);
691
+ });
692
+ }
693
+ });
694
+ const mergedScopes = Array.from(
695
+ /* @__PURE__ */ new Set([...existingCaipChainIds, ...scopes])
696
+ );
697
+ const mergedCaipAccountIds = Array.from(
698
+ /* @__PURE__ */ new Set([...existingCaipAccountIds, ...caipAccountIds])
699
+ );
700
+ const mergedSessionProperties = __spreadValues(__spreadValues({}, sessionData.sessionProperties), sessionProperties);
701
+ return {
702
+ mergedScopes,
703
+ mergedCaipAccountIds,
704
+ mergedSessionProperties
705
+ };
706
+ }
649
707
  function getOptionalScopes(scopes) {
650
708
  return scopes.reduce(
651
709
  (prev, scope) => __spreadProps(__spreadValues({}, prev), {
@@ -658,6 +716,21 @@ function getOptionalScopes(scopes) {
658
716
  {}
659
717
  );
660
718
  }
719
+ function normalizeNativeUrl(url) {
720
+ var _a2;
721
+ const httpPattern = /^https?:\/\//u;
722
+ if (httpPattern.test(url)) {
723
+ return void 0;
724
+ }
725
+ const schemeMatch = url.match(/^([^:]*):\/\//u);
726
+ const rawScheme = (_a2 = schemeMatch == null ? void 0 : schemeMatch[1]) != null ? _a2 : url;
727
+ const sanitized = rawScheme.toLowerCase().replace(/[^a-z0-9-]/gu, "-").replace(/^-+|-+$/gu, "");
728
+ const subdomain = (sanitized || "unknown").slice(0, 63).replace(/-+$/u, "");
729
+ return {
730
+ url: `https://${subdomain}.rn.dapp.local`,
731
+ nativeScheme: url
732
+ };
733
+ }
661
734
  function setupDappMetadata(options) {
662
735
  var _a2, _b;
663
736
  const platform = getPlatformType();
@@ -673,6 +746,18 @@ function setupDappMetadata(options) {
673
746
  if (!((_b = options.dapp) == null ? void 0 : _b.url)) {
674
747
  throw new Error("You must provide dapp url");
675
748
  }
749
+ if (platform === "react-native" /* ReactNative */ && options.dapp.url) {
750
+ const normalized = normalizeNativeUrl(options.dapp.url);
751
+ if (normalized) {
752
+ console.info(
753
+ `Normalizing dapp URL for React Native: "${options.dapp.url}" -> "${normalized.url}"`
754
+ );
755
+ options.dapp = __spreadProps(__spreadValues({}, options.dapp), {
756
+ url: normalized.url,
757
+ nativeScheme: normalized.nativeScheme
758
+ });
759
+ }
760
+ }
676
761
  const BASE_64_ICON_MAX_LENGTH = 163400;
677
762
  const urlPattern = /^(http|https):\/\/[^\s]*$/u;
678
763
  if (options.dapp) {
@@ -784,7 +869,7 @@ function addValidAccounts(optionalScopes, validAccounts) {
784
869
  }
785
870
  return result;
786
871
  }
787
- var import_utils, import_pako, extractFavicon;
872
+ var import_utils, import_pako, extractFavicon, MAX, idCounter, getUniqueRequestId;
788
873
  var init_utils = __esm({
789
874
  "src/multichain/utils/index.ts"() {
790
875
  "use strict";
@@ -805,6 +890,12 @@ var init_utils = __esm({
805
890
  }
806
891
  return favicon;
807
892
  };
893
+ MAX = 4294967295;
894
+ idCounter = Math.floor(Math.random() * MAX);
895
+ getUniqueRequestId = () => {
896
+ idCounter = (idCounter + 1) % MAX;
897
+ return idCounter;
898
+ };
808
899
  }
809
900
  });
810
901
 
@@ -1475,7 +1566,7 @@ trackWalletActionRejected_fn = function(options) {
1475
1566
  var import_multichain_api_client = require("@metamask/multichain-api-client");
1476
1567
  init_utils();
1477
1568
  var DEFAULT_REQUEST_TIMEOUT = 60 * 1e3;
1478
- var _notificationCallbacks, _transport, _defaultRequestOptions, _reqId, _pendingRequests, _handleResponseListener, _handleNotificationListener, _DefaultTransport_instances, notifyCallbacks_fn, isMetamaskProviderEvent_fn, handleResponse_fn, handleNotification_fn, setupMessageListener_fn;
1569
+ var _notificationCallbacks, _transport, _defaultRequestOptions, _pendingRequests, _handleResponseListener, _handleNotificationListener, _DefaultTransport_instances, notifyCallbacks_fn, isMetamaskProviderEvent_fn, handleResponse_fn, handleNotification_fn, setupMessageListener_fn;
1479
1570
  var DefaultTransport = class {
1480
1571
  constructor() {
1481
1572
  __privateAdd(this, _DefaultTransport_instances);
@@ -1484,8 +1575,6 @@ var DefaultTransport = class {
1484
1575
  __privateAdd(this, _defaultRequestOptions, {
1485
1576
  timeout: DEFAULT_REQUEST_TIMEOUT
1486
1577
  });
1487
- // Use timestamp-based ID to avoid conflicts across disconnect/reconnect cycles
1488
- __privateAdd(this, _reqId, Date.now());
1489
1578
  __privateAdd(this, _pendingRequests, /* @__PURE__ */ new Map());
1490
1579
  __privateAdd(this, _handleResponseListener);
1491
1580
  __privateAdd(this, _handleNotificationListener);
@@ -1493,8 +1582,7 @@ var DefaultTransport = class {
1493
1582
  sendEip1193Message(payload, options) {
1494
1583
  return __async(this, null, function* () {
1495
1584
  __privateMethod(this, _DefaultTransport_instances, setupMessageListener_fn).call(this);
1496
- __privateSet(this, _reqId, __privateGet(this, _reqId) + 1);
1497
- const requestId = `${__privateGet(this, _reqId)}`;
1585
+ const requestId = String(getUniqueRequestId());
1498
1586
  const request = __spreadValues({
1499
1587
  jsonrpc: "2.0",
1500
1588
  id: requestId
@@ -1559,10 +1647,6 @@ var DefaultTransport = class {
1559
1647
  proposedCaipAccountIds
1560
1648
  );
1561
1649
  if (!hasSameScopesAndAccounts) {
1562
- yield this.request(
1563
- { method: "wallet_revokeSession", params: walletSession },
1564
- __privateGet(this, _defaultRequestOptions)
1565
- );
1566
1650
  const response = yield this.request(
1567
1651
  { method: "wallet_createSession", params: createSessionParams },
1568
1652
  __privateGet(this, _defaultRequestOptions)
@@ -1589,9 +1673,14 @@ var DefaultTransport = class {
1589
1673
  });
1590
1674
  }
1591
1675
  disconnect() {
1592
- return __async(this, null, function* () {
1676
+ return __async(this, arguments, function* (scopes = []) {
1677
+ yield this.request({ method: "wallet_revokeSession", params: { scopes } });
1678
+ const response = yield this.request({ method: "wallet_getSession" });
1679
+ const { sessionScopes } = response.result;
1680
+ if (Object.keys(sessionScopes).length > 0) {
1681
+ return;
1682
+ }
1593
1683
  __privateGet(this, _notificationCallbacks).clear();
1594
- yield this.request({ method: "wallet_revokeSession", params: {} });
1595
1684
  if (__privateGet(this, _handleResponseListener)) {
1596
1685
  window.removeEventListener("message", __privateGet(this, _handleResponseListener));
1597
1686
  __privateSet(this, _handleResponseListener, void 0);
@@ -1605,7 +1694,7 @@ var DefaultTransport = class {
1605
1694
  request.reject(new Error("Transport disconnected"));
1606
1695
  }
1607
1696
  __privateGet(this, _pendingRequests).clear();
1608
- return __privateGet(this, _transport).disconnect();
1697
+ yield __privateGet(this, _transport).disconnect();
1609
1698
  });
1610
1699
  }
1611
1700
  isConnected() {
@@ -1630,11 +1719,17 @@ var DefaultTransport = class {
1630
1719
  );
1631
1720
  });
1632
1721
  }
1722
+ getStoredPendingSessionRequest() {
1723
+ return __async(this, null, function* () {
1724
+ throw new Error(
1725
+ "getStoredPendingSessionRequest is purposely not implemented for the DefaultTransport"
1726
+ );
1727
+ });
1728
+ }
1633
1729
  };
1634
1730
  _notificationCallbacks = new WeakMap();
1635
1731
  _transport = new WeakMap();
1636
1732
  _defaultRequestOptions = new WeakMap();
1637
- _reqId = new WeakMap();
1638
1733
  _pendingRequests = new WeakMap();
1639
1734
  _handleResponseListener = new WeakMap();
1640
1735
  _handleNotificationListener = new WeakMap();
@@ -1704,18 +1799,12 @@ setupMessageListener_fn = function() {
1704
1799
 
1705
1800
  // src/multichain/transports/multichainApiClientWrapper/index.ts
1706
1801
  var import_rpc_errors = require("@metamask/rpc-errors");
1707
- var MAX = 4294967295;
1708
- var idCounter = Math.floor(Math.random() * MAX);
1709
- var getUniqueId = () => {
1710
- idCounter = (idCounter + 1) % MAX;
1711
- return idCounter;
1712
- };
1713
- var _requestId, _notificationCallbacks2, _MultichainApiClientWrapperTransport_instances, walletCreateSession_fn, walletGetSession_fn, walletRevokeSession_fn, walletInvokeMethod_fn;
1802
+ init_utils();
1803
+ var _notificationCallbacks2, _MultichainApiClientWrapperTransport_instances, walletCreateSession_fn, walletGetSession_fn, walletRevokeSession_fn, walletInvokeMethod_fn;
1714
1804
  var MultichainApiClientWrapperTransport = class {
1715
1805
  constructor(metamaskConnectMultichain) {
1716
1806
  this.metamaskConnectMultichain = metamaskConnectMultichain;
1717
1807
  __privateAdd(this, _MultichainApiClientWrapperTransport_instances);
1718
- __privateAdd(this, _requestId, getUniqueId());
1719
1808
  __privateAdd(this, _notificationCallbacks2, /* @__PURE__ */ new Set());
1720
1809
  }
1721
1810
  isTransportDefined() {
@@ -1733,15 +1822,23 @@ var MultichainApiClientWrapperTransport = class {
1733
1822
  callback(data);
1734
1823
  });
1735
1824
  }
1736
- setupNotifcationListener() {
1737
- this.metamaskConnectMultichain.transport.onNotification(
1825
+ clearTransportNotificationListener() {
1826
+ var _a2;
1827
+ (_a2 = this.notificationListener) == null ? void 0 : _a2.call(this);
1828
+ this.notificationListener = void 0;
1829
+ }
1830
+ setupTransportNotificationListener() {
1831
+ if (!this.isTransportDefined() || this.notificationListener) {
1832
+ return;
1833
+ }
1834
+ this.notificationListener = this.metamaskConnectMultichain.transport.onNotification(
1738
1835
  this.notifyCallbacks.bind(this)
1739
1836
  );
1740
1837
  }
1741
1838
  connect() {
1742
1839
  return __async(this, null, function* () {
1743
1840
  console.log("\u{1F4DA} connect");
1744
- return Promise.resolve();
1841
+ yield this.metamaskConnectMultichain.emitSessionChanged();
1745
1842
  });
1746
1843
  }
1747
1844
  disconnect() {
@@ -1754,7 +1851,7 @@ var MultichainApiClientWrapperTransport = class {
1754
1851
  }
1755
1852
  request(_0) {
1756
1853
  return __async(this, arguments, function* (params, _options = {}) {
1757
- const id = __privateWrapper(this, _requestId)._++;
1854
+ const id = getUniqueRequestId();
1758
1855
  const requestPayload = __spreadValues({
1759
1856
  id,
1760
1857
  jsonrpc: "2.0"
@@ -1775,21 +1872,17 @@ var MultichainApiClientWrapperTransport = class {
1775
1872
  });
1776
1873
  }
1777
1874
  onNotification(callback) {
1778
- if (!this.isTransportDefined()) {
1779
- __privateGet(this, _notificationCallbacks2).add(callback);
1780
- return () => {
1781
- __privateGet(this, _notificationCallbacks2).delete(callback);
1782
- };
1783
- }
1784
- return this.metamaskConnectMultichain.transport.onNotification(callback);
1875
+ this.setupTransportNotificationListener();
1876
+ __privateGet(this, _notificationCallbacks2).add(callback);
1877
+ return () => {
1878
+ __privateGet(this, _notificationCallbacks2).delete(callback);
1879
+ };
1785
1880
  }
1786
1881
  };
1787
- _requestId = new WeakMap();
1788
1882
  _notificationCallbacks2 = new WeakMap();
1789
1883
  _MultichainApiClientWrapperTransport_instances = new WeakSet();
1790
1884
  walletCreateSession_fn = function(request) {
1791
1885
  return __async(this, null, function* () {
1792
- console.log("\u{1F4DA} #walletCreateSession", request);
1793
1886
  const createSessionParams = request.params;
1794
1887
  const scopes = Object.keys(__spreadValues(__spreadValues({}, createSessionParams.optionalScopes), createSessionParams.requiredScopes));
1795
1888
  const scopeAccounts = [];
@@ -1835,11 +1928,14 @@ walletGetSession_fn = function(request) {
1835
1928
  };
1836
1929
  walletRevokeSession_fn = function(request) {
1837
1930
  return __async(this, null, function* () {
1931
+ var _a2;
1838
1932
  if (!this.isTransportDefined()) {
1839
1933
  return { jsonrpc: "2.0", id: request.id, result: true };
1840
1934
  }
1935
+ const revokeSessionParams = request.params;
1936
+ const scopes = (_a2 = revokeSessionParams == null ? void 0 : revokeSessionParams.scopes) != null ? _a2 : [];
1841
1937
  try {
1842
- this.metamaskConnectMultichain.disconnect();
1938
+ yield this.metamaskConnectMultichain.disconnect(scopes);
1843
1939
  return { jsonrpc: "2.0", id: request.id, result: true };
1844
1940
  } catch (_error) {
1845
1941
  return { jsonrpc: "2.0", id: request.id, result: false };
@@ -1863,6 +1959,7 @@ walletInvokeMethod_fn = function(request) {
1863
1959
  // src/multichain/transports/mwp/index.ts
1864
1960
  var import_mobile_wallet_protocol_core = require("@metamask/mobile-wallet-protocol-core");
1865
1961
  var import_multichain_api_client2 = require("@metamask/multichain-api-client");
1962
+ var import_rpc_errors2 = require("@metamask/rpc-errors");
1866
1963
  init_domain();
1867
1964
  init_utils();
1868
1965
 
@@ -1877,6 +1974,7 @@ var DEFAULT_RESUME_TIMEOUT = 10 * 1e3;
1877
1974
  var SESSION_STORE_KEY = "cache_wallet_getSession";
1878
1975
  var ACCOUNTS_STORE_KEY = "cache_eth_accounts";
1879
1976
  var CHAIN_STORE_KEY = "cache_eth_chainId";
1977
+ var PENDING_SESSION_REQUEST_KEY = "pending_session_request";
1880
1978
  var CACHED_METHOD_LIST = [
1881
1979
  "wallet_getSession",
1882
1980
  "wallet_createSession",
@@ -1896,10 +1994,15 @@ var MWPTransport = class {
1896
1994
  this.dappClient = dappClient;
1897
1995
  this.kvstore = kvstore;
1898
1996
  this.options = options;
1899
- this.__reqId = 0;
1900
1997
  this.__pendingRequests = /* @__PURE__ */ new Map();
1901
1998
  this.notificationCallbacks = /* @__PURE__ */ new Set();
1902
1999
  this.dappClient.on("message", this.handleMessage.bind(this));
2000
+ this.dappClient.on("session_request", (sessionRequest) => {
2001
+ this.currentSessionRequest = sessionRequest;
2002
+ this.kvstore.set(PENDING_SESSION_REQUEST_KEY, JSON.stringify(sessionRequest)).catch((err) => {
2003
+ logger("Failed to store pending session request", err);
2004
+ });
2005
+ });
1903
2006
  if (typeof window !== "undefined" && typeof window.addEventListener !== "undefined") {
1904
2007
  this.windowFocusHandler = this.onWindowFocus.bind(this);
1905
2008
  window.addEventListener("focus", this.windowFocusHandler);
@@ -1914,6 +2017,34 @@ var MWPTransport = class {
1914
2017
  get sessionRequest() {
1915
2018
  return this.currentSessionRequest;
1916
2019
  }
2020
+ /**
2021
+ * Returns the stored pending session request from the dappClient session_request event, if any.
2022
+ *
2023
+ * @returns The stored SessionRequest, or null if none or invalid.
2024
+ */
2025
+ getStoredPendingSessionRequest() {
2026
+ return __async(this, null, function* () {
2027
+ try {
2028
+ const raw = yield this.kvstore.get(PENDING_SESSION_REQUEST_KEY);
2029
+ if (!raw) {
2030
+ return null;
2031
+ }
2032
+ return JSON.parse(raw);
2033
+ } catch (e) {
2034
+ return null;
2035
+ }
2036
+ });
2037
+ }
2038
+ /**
2039
+ * Removes the stored pending session request from the KVStore.
2040
+ * This is necessary to ensure that ConnectMultichain is able to correctly
2041
+ * infer the MWP Transport connection attempt status.
2042
+ */
2043
+ removeStoredPendingSessionRequest() {
2044
+ return __async(this, null, function* () {
2045
+ yield this.kvstore.delete(PENDING_SESSION_REQUEST_KEY);
2046
+ });
2047
+ }
1917
2048
  onWindowFocus() {
1918
2049
  if (!this.isConnected()) {
1919
2050
  this.dappClient.reconnect();
@@ -1930,6 +2061,18 @@ var MWPTransport = class {
1930
2061
  request.reject(error);
1931
2062
  }
1932
2063
  }
2064
+ parseWalletError(errorPayload) {
2065
+ const errorData = errorPayload;
2066
+ if (typeof errorData.code === "number" && typeof errorData.message === "string") {
2067
+ const { code, message: message2 } = errorData;
2068
+ if (code >= 1e3 && code <= 4999) {
2069
+ return import_rpc_errors2.providerErrors.custom({ code, message: message2 });
2070
+ }
2071
+ return new import_rpc_errors2.JsonRpcError(code, message2);
2072
+ }
2073
+ const message = errorPayload instanceof Error ? errorPayload.message : JSON.stringify(errorPayload);
2074
+ return import_rpc_errors2.rpcErrors.internal({ message });
2075
+ }
1933
2076
  handleMessage(message) {
1934
2077
  if (typeof message === "object" && message !== null) {
1935
2078
  if ("data" in message) {
@@ -1937,6 +2080,12 @@ var MWPTransport = class {
1937
2080
  if ("id" in messagePayload && typeof messagePayload.id === "string") {
1938
2081
  const request = this.pendingRequests.get(messagePayload.id);
1939
2082
  if (request) {
2083
+ clearTimeout(request.timeout);
2084
+ if ("error" in messagePayload && messagePayload.error) {
2085
+ this.pendingRequests.delete(messagePayload.id);
2086
+ request.reject(this.parseWalletError(messagePayload.error));
2087
+ return;
2088
+ }
1940
2089
  const requestWithName = __spreadProps(__spreadValues({}, messagePayload), {
1941
2090
  method: request.method === "wallet_getSession" || request.method === "wallet_createSession" ? "wallet_sessionChanged" : request.method
1942
2091
  });
@@ -1944,7 +2093,6 @@ var MWPTransport = class {
1944
2093
  method: request.method === "wallet_getSession" || request.method === "wallet_createSession" ? "wallet_sessionChanged" : request.method,
1945
2094
  params: requestWithName.result
1946
2095
  });
1947
- clearTimeout(request.timeout);
1948
2096
  this.notifyCallbacks(notification);
1949
2097
  request.resolve(requestWithName);
1950
2098
  this.pendingRequests.delete(messagePayload.id);
@@ -2034,6 +2182,7 @@ var MWPTransport = class {
2034
2182
  }
2035
2183
  walletSession = response.result;
2036
2184
  }
2185
+ yield this.removeStoredPendingSessionRequest();
2037
2186
  this.notifyCallbacks({
2038
2187
  method: "wallet_sessionChanged",
2039
2188
  params: walletSession
@@ -2049,7 +2198,7 @@ var MWPTransport = class {
2049
2198
  return __async(this, null, function* () {
2050
2199
  const request = __spreadValues({
2051
2200
  jsonrpc: "2.0",
2052
- id: `${this.__reqId++}`
2201
+ id: String(getUniqueRequestId())
2053
2202
  }, payload);
2054
2203
  const cachedWalletSession = yield this.getCachedResponse(request);
2055
2204
  if (cachedWalletSession) {
@@ -2083,8 +2232,13 @@ var MWPTransport = class {
2083
2232
  const { dappClient } = this;
2084
2233
  const session = yield this.getActiveSession();
2085
2234
  if (session) {
2086
- logger("active session found", session);
2235
+ logger("active session found", {
2236
+ id: session.id,
2237
+ channel: session.channel,
2238
+ expiresAt: session.expiresAt
2239
+ });
2087
2240
  }
2241
+ const storedSessionRequestBeforeConnectionAttempt = yield this.getStoredPendingSessionRequest();
2088
2242
  let timeout;
2089
2243
  let initialConnectionMessageHandler;
2090
2244
  const connectionPromise = new Promise((resolve, reject) => __async(this, null, function* () {
@@ -2115,33 +2269,35 @@ var MWPTransport = class {
2115
2269
  };
2116
2270
  const request = {
2117
2271
  jsonrpc: "2.0",
2118
- id: `${this.__reqId++}`,
2272
+ id: String(getUniqueRequestId()),
2119
2273
  method: "wallet_createSession",
2120
2274
  params: sessionRequest
2121
2275
  };
2122
2276
  initialConnectionMessageHandler = (message) => __async(this, null, function* () {
2123
- if (typeof message === "object" && message !== null) {
2124
- if ("data" in message) {
2125
- const messagePayload = message.data;
2126
- if (messagePayload.method === "wallet_createSession" || messagePayload.method === "wallet_sessionChanged") {
2127
- if (messagePayload.error) {
2128
- if (initialConnectionMessageHandler) {
2129
- this.dappClient.off(
2130
- "message",
2131
- initialConnectionMessageHandler
2132
- );
2133
- }
2134
- return rejectConnection(messagePayload.error);
2135
- }
2136
- yield this.storeWalletSession(
2137
- request,
2138
- messagePayload
2139
- );
2140
- this.notifyCallbacks(messagePayload);
2141
- return resolveConnection();
2142
- }
2143
- }
2277
+ if (typeof message !== "object" || message === null) {
2278
+ return;
2279
+ }
2280
+ if (!("data" in message)) {
2281
+ return;
2144
2282
  }
2283
+ const messagePayload = message.data;
2284
+ const isMatchingId = messagePayload.id === request.id;
2285
+ const isMatchingMethod = messagePayload.method === "wallet_createSession" || messagePayload.method === "wallet_sessionChanged";
2286
+ if (!isMatchingId && !isMatchingMethod) {
2287
+ return;
2288
+ }
2289
+ if (messagePayload.error) {
2290
+ return rejectConnection(
2291
+ this.parseWalletError(messagePayload.error)
2292
+ );
2293
+ }
2294
+ yield this.storeWalletSession(
2295
+ request,
2296
+ messagePayload
2297
+ );
2298
+ yield this.removeStoredPendingSessionRequest();
2299
+ this.notifyCallbacks(messagePayload);
2300
+ return resolveConnection();
2145
2301
  });
2146
2302
  this.dappClient.on("message", initialConnectionMessageHandler);
2147
2303
  dappClient.connect({
@@ -2162,14 +2318,18 @@ var MWPTransport = class {
2162
2318
  }
2163
2319
  );
2164
2320
  }
2165
- timeout = setTimeout(() => {
2166
- reject(new import_multichain_api_client2.TransportTimeoutError());
2167
- }, this.options.connectionTimeout);
2321
+ timeout = setTimeout(
2322
+ () => {
2323
+ reject(new import_multichain_api_client2.TransportTimeoutError());
2324
+ },
2325
+ storedSessionRequestBeforeConnectionAttempt ? this.options.resumeTimeout : this.options.connectionTimeout
2326
+ );
2168
2327
  connection.then(resolve).catch(reject);
2169
2328
  }));
2170
- return connectionPromise.catch((error) => {
2329
+ return connectionPromise.catch((error) => __async(this, null, function* () {
2330
+ yield this.dappClient.disconnect();
2171
2331
  throw error;
2172
- }).finally(() => {
2332
+ })).finally(() => {
2173
2333
  if (timeout) {
2174
2334
  clearTimeout(timeout);
2175
2335
  }
@@ -2177,24 +2337,68 @@ var MWPTransport = class {
2177
2337
  this.dappClient.off("message", initialConnectionMessageHandler);
2178
2338
  initialConnectionMessageHandler = void 0;
2179
2339
  }
2340
+ this.removeStoredPendingSessionRequest();
2180
2341
  });
2181
2342
  });
2182
2343
  }
2183
2344
  /**
2184
2345
  * Disconnects from the Mobile Wallet Protocol
2185
2346
  *
2347
+ * @param [scopes] - The scopes to revoke. If not provided or empty, all scopes will be revoked.
2186
2348
  * @returns Nothing
2187
2349
  */
2188
2350
  disconnect() {
2189
- return __async(this, null, function* () {
2190
- if (typeof window !== "undefined" && typeof window.removeEventListener !== "undefined" && this.windowFocusHandler) {
2191
- window.removeEventListener("focus", this.windowFocusHandler);
2192
- this.windowFocusHandler = void 0;
2193
- }
2194
- this.kvstore.delete(SESSION_STORE_KEY);
2195
- this.kvstore.delete(ACCOUNTS_STORE_KEY);
2196
- this.kvstore.delete(CHAIN_STORE_KEY);
2197
- return this.dappClient.disconnect();
2351
+ return __async(this, arguments, function* (scopes = []) {
2352
+ var _a2, _b;
2353
+ const cachedSession = yield this.getCachedResponse({
2354
+ jsonrpc: "2.0",
2355
+ id: "0",
2356
+ method: "wallet_getSession"
2357
+ });
2358
+ const cachedSessionScopes = (_b = (_a2 = cachedSession == null ? void 0 : cachedSession.result) == null ? void 0 : _a2.sessionScopes) != null ? _b : {};
2359
+ const remainingScopes = scopes.length === 0 ? [] : Object.keys(cachedSessionScopes).filter(
2360
+ (scope) => !scopes.includes(scope)
2361
+ );
2362
+ const newSessionScopes = Object.fromEntries(
2363
+ Object.entries(cachedSessionScopes).filter(
2364
+ ([key]) => remainingScopes.includes(key)
2365
+ )
2366
+ );
2367
+ this.request({ method: "wallet_revokeSession", params: { scopes } }).catch(
2368
+ (err) => {
2369
+ console.error("error revoking session", err);
2370
+ }
2371
+ );
2372
+ const remainingScopesIncludeEip155 = remainingScopes.some(
2373
+ (scope) => scope.includes("eip155")
2374
+ );
2375
+ if (!remainingScopesIncludeEip155) {
2376
+ this.kvstore.delete(ACCOUNTS_STORE_KEY);
2377
+ this.kvstore.delete(CHAIN_STORE_KEY);
2378
+ }
2379
+ if (remainingScopes.length > 0) {
2380
+ this.kvstore.set(
2381
+ SESSION_STORE_KEY,
2382
+ JSON.stringify({
2383
+ result: {
2384
+ sessionScopes: newSessionScopes
2385
+ }
2386
+ })
2387
+ );
2388
+ } else {
2389
+ this.kvstore.delete(SESSION_STORE_KEY);
2390
+ if (typeof window !== "undefined" && typeof window.removeEventListener !== "undefined" && this.windowFocusHandler) {
2391
+ window.removeEventListener("focus", this.windowFocusHandler);
2392
+ this.windowFocusHandler = void 0;
2393
+ }
2394
+ yield this.dappClient.disconnect();
2395
+ }
2396
+ this.notifyCallbacks({
2397
+ method: "wallet_sessionChanged",
2398
+ params: {
2399
+ sessionScopes: newSessionScopes
2400
+ }
2401
+ });
2198
2402
  });
2199
2403
  }
2200
2404
  /**
@@ -2300,7 +2504,7 @@ var MWPTransport = class {
2300
2504
  return __async(this, null, function* () {
2301
2505
  const request = __spreadValues({
2302
2506
  jsonrpc: "2.0",
2303
- id: `${this.__reqId++}`
2507
+ id: String(getUniqueRequestId())
2304
2508
  }, payload);
2305
2509
  const cachedWalletSession = yield this.getCachedResponse(request);
2306
2510
  if (cachedWalletSession) {
@@ -2382,6 +2586,7 @@ var MWPTransport = class {
2382
2586
  const timeoutPromise = new Promise((_resolve, reject) => {
2383
2587
  setTimeout(() => {
2384
2588
  unsubscribe();
2589
+ this.removeStoredPendingSessionRequest();
2385
2590
  reject(new import_multichain_api_client2.TransportTimeoutError());
2386
2591
  }, this.options.resumeTimeout);
2387
2592
  });
@@ -2420,7 +2625,8 @@ var keymanager = new KeyManager();
2420
2625
  // src/multichain/index.ts
2421
2626
  init_utils();
2422
2627
  var logger2 = createLogger("metamask-sdk:core");
2423
- var _a, _provider, _providerTransportWrapper, _transport2, _dappClient, _beforeUnloadListener, _listener, _sdkInfo, _MetaMaskConnectMultichain_instances, setupAnalytics_fn, onTransportNotification_fn, getStoredTransport_fn, setupTransport_fn, init_fn, createDappClient_fn, setupMWP_fn, onBeforeUnload_fn, createBeforeUnloadListener_fn, renderInstallModalAsync_fn, showInstallModal_fn, headlessConnect_fn, setupDefaultTransport_fn, deeplinkConnect_fn, handleConnection_fn;
2628
+ var SINGLETON_KEY = "__METAMASK_CONNECT_MULTICHAIN_SINGLETON__";
2629
+ var _a, _provider, _providerTransportWrapper, _transport2, _dappClient, _beforeUnloadListener, _listener, _sdkInfo, _MetaMaskConnectMultichain_instances, setupAnalytics_fn, onTransportNotification_fn, getStoredTransport_fn, setupTransport_fn, init_fn, createDappClient_fn, setupMWP_fn, onBeforeUnload_fn, createBeforeUnloadListener_fn, renderInstallModalAsync_fn, showInstallModal_fn, headlessConnect_fn, setupDefaultTransport_fn, deeplinkConnect_fn, handleConnection_fn, getCaipSession_fn, openConnectDeeplinkIfNeeded_fn;
2424
2630
  var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends MultichainCore {
2425
2631
  constructor(options) {
2426
2632
  var _a2, _b, _c, _d, _e, _f;
@@ -2485,27 +2691,54 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2485
2691
  get transportType() {
2486
2692
  return __privateGet(this, _transport2) instanceof MWPTransport ? "mwp" /* MWP */ : "browser" /* Browser */;
2487
2693
  }
2694
+ // Creates a singleton instance of MetaMaskConnectMultichain.
2695
+ // If the singleton already exists, it merges the incoming options with the
2696
+ // existing singleton options for the following keys: `api.supportedNetworks`,
2697
+ // `ui.*`, `mobile.*`, `transport.extensionId`, `debug`. Take note that the
2698
+ // value for `dapp` is not merged as it does not make sense for subsequent calls to
2699
+ // `createMultichainClient` to have a different `dapp` value.
2488
2700
  static create(options) {
2489
2701
  return __async(this, null, function* () {
2490
- var _a2;
2491
- const instance = new _MetaMaskConnectMultichain(options);
2492
- const isEnabled2 = yield isEnabled(
2493
- "metamask-sdk:core",
2494
- instance.options.storage
2495
- );
2496
- if (isEnabled2) {
2497
- enableDebug("metamask-sdk:core");
2702
+ const globalObject = getGlobalObject();
2703
+ const existing = globalObject[SINGLETON_KEY];
2704
+ if (existing) {
2705
+ const instance = yield existing;
2706
+ instance.mergeOptions(options);
2707
+ if (options.debug) {
2708
+ enableDebug("metamask-sdk:*");
2709
+ }
2710
+ return instance;
2498
2711
  }
2499
- yield __privateMethod(_a2 = instance, _MetaMaskConnectMultichain_instances, init_fn).call(_a2);
2500
- return instance;
2712
+ const instancePromise = (() => __async(null, null, function* () {
2713
+ var _a2;
2714
+ const instance = new _MetaMaskConnectMultichain(options);
2715
+ const isEnabled2 = yield isEnabled(
2716
+ "metamask-sdk:core",
2717
+ instance.options.storage
2718
+ );
2719
+ if (isEnabled2) {
2720
+ enableDebug("metamask-sdk:core");
2721
+ }
2722
+ yield __privateMethod(_a2 = instance, _MetaMaskConnectMultichain_instances, init_fn).call(_a2);
2723
+ return instance;
2724
+ }))();
2725
+ globalObject[SINGLETON_KEY] = instancePromise;
2726
+ instancePromise.catch((error) => {
2727
+ globalObject[SINGLETON_KEY] = void 0;
2728
+ console.error("Error initializing MetaMaskConnectMultichain", error);
2729
+ });
2730
+ return instancePromise;
2501
2731
  });
2502
2732
  }
2503
2733
  // TODO: make this into param object
2504
2734
  connect(scopes, caipAccountIds, sessionProperties, forceRequest) {
2505
2735
  return __async(this, null, function* () {
2506
2736
  var _a2;
2507
- if (this.status !== "connected") {
2508
- yield this.disconnect();
2737
+ if (this.status === "connecting" && this.transportType === "mwp" /* MWP */) {
2738
+ yield __privateMethod(this, _MetaMaskConnectMultichain_instances, openConnectDeeplinkIfNeeded_fn).call(this);
2739
+ throw new Error(
2740
+ "Existing connection is pending. Please check your MetaMask Mobile app to continue."
2741
+ );
2509
2742
  }
2510
2743
  const { ui } = this.options;
2511
2744
  const platformType = getPlatformType();
@@ -2535,12 +2768,19 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2535
2768
  } catch (error) {
2536
2769
  logger2("Error tracking connection_initiated event", error);
2537
2770
  }
2538
- const nonEmptySessionProperites = Object.keys(sessionProperties != null ? sessionProperties : {}).length > 0 ? sessionProperties : void 0;
2771
+ const sessionData = yield __privateMethod(this, _MetaMaskConnectMultichain_instances, getCaipSession_fn).call(this);
2772
+ const { mergedScopes, mergedCaipAccountIds, mergedSessionProperties } = mergeRequestedSessionWithExisting(
2773
+ sessionData,
2774
+ scopes,
2775
+ caipAccountIds,
2776
+ sessionProperties
2777
+ );
2778
+ const nonEmptySessionProperties = Object.keys(mergedSessionProperties != null ? mergedSessionProperties : {}).length > 0 ? mergedSessionProperties : void 0;
2539
2779
  if (((_a2 = __privateGet(this, _transport2)) == null ? void 0 : _a2.isConnected()) && !secure) {
2540
2780
  return __privateMethod(this, _MetaMaskConnectMultichain_instances, handleConnection_fn).call(this, __privateGet(this, _transport2).connect({
2541
- scopes,
2542
- caipAccountIds,
2543
- sessionProperties: nonEmptySessionProperites,
2781
+ scopes: mergedScopes,
2782
+ caipAccountIds: mergedCaipAccountIds,
2783
+ sessionProperties: nonEmptySessionProperties,
2544
2784
  forceRequest
2545
2785
  }).then(() => __async(this, null, function* () {
2546
2786
  if (__privateGet(this, _transport2) instanceof MWPTransport) {
@@ -2552,27 +2792,27 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2552
2792
  if (platformType === "in-app-browser" /* MetaMaskMobileWebview */) {
2553
2793
  const defaultTransport = yield __privateMethod(this, _MetaMaskConnectMultichain_instances, setupDefaultTransport_fn).call(this);
2554
2794
  return __privateMethod(this, _MetaMaskConnectMultichain_instances, handleConnection_fn).call(this, defaultTransport.connect({
2555
- scopes,
2556
- caipAccountIds,
2557
- sessionProperties: nonEmptySessionProperites,
2795
+ scopes: mergedScopes,
2796
+ caipAccountIds: mergedCaipAccountIds,
2797
+ sessionProperties: nonEmptySessionProperties,
2558
2798
  forceRequest
2559
2799
  }), scopes, transportType);
2560
2800
  }
2561
2801
  if (isWeb && hasExtensionInstalled && preferExtension) {
2562
2802
  const defaultTransport = yield __privateMethod(this, _MetaMaskConnectMultichain_instances, setupDefaultTransport_fn).call(this);
2563
2803
  return __privateMethod(this, _MetaMaskConnectMultichain_instances, handleConnection_fn).call(this, defaultTransport.connect({
2564
- scopes,
2565
- caipAccountIds,
2566
- sessionProperties: nonEmptySessionProperites,
2804
+ scopes: mergedScopes,
2805
+ caipAccountIds: mergedCaipAccountIds,
2806
+ sessionProperties: nonEmptySessionProperties,
2567
2807
  forceRequest
2568
2808
  }), scopes, transportType);
2569
2809
  }
2570
2810
  yield __privateMethod(this, _MetaMaskConnectMultichain_instances, setupMWP_fn).call(this);
2571
2811
  const shouldShowInstallModal = hasExtensionInstalled ? showInstallModal : !preferExtension || showInstallModal;
2572
2812
  if (secure && !shouldShowInstallModal) {
2573
- return __privateMethod(this, _MetaMaskConnectMultichain_instances, handleConnection_fn).call(this, __privateMethod(this, _MetaMaskConnectMultichain_instances, deeplinkConnect_fn).call(this, scopes, caipAccountIds, nonEmptySessionProperites), scopes, transportType);
2813
+ return __privateMethod(this, _MetaMaskConnectMultichain_instances, handleConnection_fn).call(this, __privateMethod(this, _MetaMaskConnectMultichain_instances, deeplinkConnect_fn).call(this, mergedScopes, mergedCaipAccountIds, nonEmptySessionProperties), scopes, transportType);
2574
2814
  }
2575
- return __privateMethod(this, _MetaMaskConnectMultichain_instances, handleConnection_fn).call(this, __privateMethod(this, _MetaMaskConnectMultichain_instances, showInstallModal_fn).call(this, shouldShowInstallModal, scopes, caipAccountIds, nonEmptySessionProperites), scopes, transportType);
2815
+ return __privateMethod(this, _MetaMaskConnectMultichain_instances, handleConnection_fn).call(this, __privateMethod(this, _MetaMaskConnectMultichain_instances, showInstallModal_fn).call(this, shouldShowInstallModal, mergedScopes, mergedCaipAccountIds, nonEmptySessionProperties), scopes, transportType);
2576
2816
  });
2577
2817
  }
2578
2818
  emit(event, args) {
@@ -2581,18 +2821,24 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2581
2821
  super.emit(event, args);
2582
2822
  }
2583
2823
  disconnect() {
2584
- return __async(this, null, function* () {
2824
+ return __async(this, arguments, function* (scopes = []) {
2585
2825
  var _a2, _b, _c;
2586
- yield (_a2 = __privateGet(this, _listener)) == null ? void 0 : _a2.call(this);
2587
- (_b = __privateGet(this, _beforeUnloadListener)) == null ? void 0 : _b.call(this);
2588
- yield (_c = __privateGet(this, _transport2)) == null ? void 0 : _c.disconnect();
2589
- yield this.storage.removeTransport();
2590
- this.emit("stateChanged", "disconnected");
2591
- __privateSet(this, _listener, void 0);
2592
- __privateSet(this, _beforeUnloadListener, void 0);
2593
- __privateSet(this, _transport2, void 0);
2594
- __privateGet(this, _providerTransportWrapper).clearNotificationCallbacks();
2595
- __privateSet(this, _dappClient, void 0);
2826
+ const sessionData = yield __privateMethod(this, _MetaMaskConnectMultichain_instances, getCaipSession_fn).call(this);
2827
+ const remainingScopes = scopes.length === 0 ? [] : Object.keys(sessionData.sessionScopes).filter(
2828
+ (scope) => !scopes.includes(scope)
2829
+ );
2830
+ yield (_a2 = __privateGet(this, _transport2)) == null ? void 0 : _a2.disconnect(scopes);
2831
+ if (remainingScopes.length === 0) {
2832
+ yield (_b = __privateGet(this, _listener)) == null ? void 0 : _b.call(this);
2833
+ (_c = __privateGet(this, _beforeUnloadListener)) == null ? void 0 : _c.call(this);
2834
+ yield this.storage.removeTransport();
2835
+ __privateSet(this, _listener, void 0);
2836
+ __privateSet(this, _beforeUnloadListener, void 0);
2837
+ __privateSet(this, _transport2, void 0);
2838
+ __privateGet(this, _providerTransportWrapper).clearTransportNotificationListener();
2839
+ __privateSet(this, _dappClient, void 0);
2840
+ this.status = "disconnected";
2841
+ }
2596
2842
  });
2597
2843
  }
2598
2844
  invokeMethod(request) {
@@ -2604,7 +2850,7 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2604
2850
  });
2605
2851
  }
2606
2852
  // DRY THIS WITH REQUEST ROUTER
2607
- openDeeplinkIfNeeded() {
2853
+ openSimpleDeeplinkIfNeeded() {
2608
2854
  const { ui, mobile } = this.options;
2609
2855
  const { showInstallModal = false } = ui != null ? ui : {};
2610
2856
  const secure = isSecure();
@@ -2624,6 +2870,23 @@ var _MetaMaskConnectMultichain = class _MetaMaskConnectMultichain extends Multic
2624
2870
  }), 10);
2625
2871
  }
2626
2872
  }
2873
+ // Provides a way for ecosystem clients (EVM, Solana, etc.) to get the current CAIP session data
2874
+ // when instantiating themselves (as they would have already missed any initial sessionChanged events emitted by ConnectMultichain)
2875
+ // without having to concern themselves with the current transport connection status.
2876
+ emitSessionChanged() {
2877
+ return __async(this, null, function* () {
2878
+ var _a2;
2879
+ const emptySession = { sessionScopes: {} };
2880
+ if (this.status !== "connected" && this.status !== "connecting") {
2881
+ this.emit("wallet_sessionChanged", emptySession);
2882
+ return;
2883
+ }
2884
+ const response = yield this.transport.request({
2885
+ method: "wallet_getSession"
2886
+ });
2887
+ this.emit("wallet_sessionChanged", (_a2 = response.result) != null ? _a2 : emptySession);
2888
+ });
2889
+ }
2627
2890
  };
2628
2891
  _provider = new WeakMap();
2629
2892
  _providerTransportWrapper = new WeakMap();
@@ -2673,7 +2936,7 @@ getStoredTransport_fn = function() {
2673
2936
  if (hasExtensionInstalled) {
2674
2937
  const apiTransport = new DefaultTransport();
2675
2938
  __privateSet(this, _transport2, apiTransport);
2676
- __privateGet(this, _providerTransportWrapper).setupNotifcationListener();
2939
+ __privateGet(this, _providerTransportWrapper).setupTransportNotificationListener();
2677
2940
  __privateSet(this, _listener, apiTransport.onNotification(
2678
2941
  __privateMethod(this, _MetaMaskConnectMultichain_instances, onTransportNotification_fn).bind(this)
2679
2942
  ));
@@ -2685,7 +2948,7 @@ getStoredTransport_fn = function() {
2685
2948
  const apiTransport = new MWPTransport(dappClient, kvstore);
2686
2949
  __privateSet(this, _dappClient, dappClient);
2687
2950
  __privateSet(this, _transport2, apiTransport);
2688
- __privateGet(this, _providerTransportWrapper).setupNotifcationListener();
2951
+ __privateGet(this, _providerTransportWrapper).setupTransportNotificationListener();
2689
2952
  __privateSet(this, _listener, apiTransport.onNotification(
2690
2953
  __privateMethod(this, _MetaMaskConnectMultichain_instances, onTransportNotification_fn).bind(this)
2691
2954
  ));
@@ -2717,25 +2980,17 @@ setupTransport_fn = function() {
2717
2980
  };
2718
2981
  init_fn = function() {
2719
2982
  return __async(this, null, function* () {
2720
- var _a2;
2721
2983
  try {
2722
- if (typeof window !== "undefined" && ((_a2 = window.mmsdk) == null ? void 0 : _a2.isInitialized)) {
2723
- logger2("MetaMaskSDK: init already initialized");
2724
- } else {
2725
- yield __privateMethod(this, _MetaMaskConnectMultichain_instances, setupAnalytics_fn).call(this);
2726
- yield __privateMethod(this, _MetaMaskConnectMultichain_instances, setupTransport_fn).call(this);
2727
- try {
2728
- const baseProps = yield getBaseAnalyticsProperties(
2729
- this.options,
2730
- this.storage
2731
- );
2732
- import_analytics4.analytics.track("mmconnect_initialized", baseProps);
2733
- } catch (error) {
2734
- logger2("Error tracking initialized event", error);
2735
- }
2736
- if (typeof window !== "undefined") {
2737
- window.mmsdk = this;
2738
- }
2984
+ yield __privateMethod(this, _MetaMaskConnectMultichain_instances, setupAnalytics_fn).call(this);
2985
+ yield __privateMethod(this, _MetaMaskConnectMultichain_instances, setupTransport_fn).call(this);
2986
+ try {
2987
+ const baseProps = yield getBaseAnalyticsProperties(
2988
+ this.options,
2989
+ this.storage
2990
+ );
2991
+ import_analytics4.analytics.track("mmconnect_initialized", baseProps);
2992
+ } catch (error) {
2993
+ logger2("Error tracking initialized event", error);
2739
2994
  }
2740
2995
  } catch (error) {
2741
2996
  yield this.storage.removeTransport();
@@ -2771,7 +3026,7 @@ setupMWP_fn = function() {
2771
3026
  __privateSet(this, _dappClient, dappClient);
2772
3027
  const apiTransport = new MWPTransport(dappClient, kvstore);
2773
3028
  __privateSet(this, _transport2, apiTransport);
2774
- __privateGet(this, _providerTransportWrapper).setupNotifcationListener();
3029
+ __privateGet(this, _providerTransportWrapper).setupTransportNotificationListener();
2775
3030
  __privateSet(this, _listener, this.transport.onNotification(
2776
3031
  __privateMethod(this, _MetaMaskConnectMultichain_instances, onTransportNotification_fn).bind(this)
2777
3032
  ));
@@ -2787,15 +3042,13 @@ onBeforeUnload_fn = function() {
2787
3042
  });
2788
3043
  };
2789
3044
  createBeforeUnloadListener_fn = function() {
3045
+ const handler = __privateMethod(this, _MetaMaskConnectMultichain_instances, onBeforeUnload_fn).bind(this);
2790
3046
  if (typeof window !== "undefined" && typeof window.addEventListener !== "undefined") {
2791
- window.addEventListener("beforeunload", __privateMethod(this, _MetaMaskConnectMultichain_instances, onBeforeUnload_fn).bind(this));
3047
+ window.addEventListener("beforeunload", handler);
2792
3048
  }
2793
3049
  return () => {
2794
3050
  if (typeof window !== "undefined" && typeof window.removeEventListener !== "undefined") {
2795
- window.removeEventListener(
2796
- "beforeunload",
2797
- __privateMethod(this, _MetaMaskConnectMultichain_instances, onBeforeUnload_fn).bind(this)
2798
- );
3051
+ window.removeEventListener("beforeunload", handler);
2799
3052
  }
2800
3053
  };
2801
3054
  };
@@ -2840,13 +3093,14 @@ renderInstallModalAsync_fn = function(desktopPreferred, scopes, caipAccountIds,
2840
3093
  if (error instanceof import_mobile_wallet_protocol_core2.ProtocolError) {
2841
3094
  if (error.code !== import_mobile_wallet_protocol_core2.ErrorCode.REQUEST_EXPIRED) {
2842
3095
  this.status = "disconnected";
3096
+ yield this.options.ui.factory.unload(error);
2843
3097
  reject(error);
2844
3098
  }
2845
3099
  } else {
2846
3100
  this.status = "disconnected";
2847
- reject(
2848
- error instanceof Error ? error : new Error(String(error))
2849
- );
3101
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
3102
+ yield this.options.ui.factory.unload(normalizedError);
3103
+ reject(normalizedError);
2850
3104
  }
2851
3105
  }
2852
3106
  }))().catch(() => {
@@ -2933,7 +3187,7 @@ setupDefaultTransport_fn = function() {
2933
3187
  __privateMethod(this, _MetaMaskConnectMultichain_instances, onTransportNotification_fn).bind(this)
2934
3188
  ));
2935
3189
  __privateSet(this, _transport2, transport);
2936
- __privateGet(this, _providerTransportWrapper).setupNotifcationListener();
3190
+ __privateGet(this, _providerTransportWrapper).setupTransportNotificationListener();
2937
3191
  return transport;
2938
3192
  });
2939
3193
  };
@@ -2960,7 +3214,7 @@ deeplinkConnect_fn = function(scopes, caipAccountIds, sessionProperties) {
2960
3214
  let timeout;
2961
3215
  if (this.transport.isConnected()) {
2962
3216
  timeout = setTimeout(() => {
2963
- this.openDeeplinkIfNeeded();
3217
+ this.openSimpleDeeplinkIfNeeded();
2964
3218
  }, 250);
2965
3219
  } else {
2966
3220
  this.dappClient.once(
@@ -3043,6 +3297,53 @@ handleConnection_fn = function(promise, scopes, transportType) {
3043
3297
  }));
3044
3298
  });
3045
3299
  };
3300
+ getCaipSession_fn = function() {
3301
+ return __async(this, null, function* () {
3302
+ let sessionData = {
3303
+ sessionScopes: {},
3304
+ sessionProperties: {}
3305
+ };
3306
+ if (this.status === "connected") {
3307
+ const response = yield this.transport.request({
3308
+ method: "wallet_getSession"
3309
+ });
3310
+ if (response.result) {
3311
+ sessionData = response.result;
3312
+ }
3313
+ }
3314
+ return sessionData;
3315
+ });
3316
+ };
3317
+ openConnectDeeplinkIfNeeded_fn = function() {
3318
+ return __async(this, null, function* () {
3319
+ var _a2, _b;
3320
+ const { ui } = this.options;
3321
+ const { showInstallModal = false } = ui != null ? ui : {};
3322
+ const secure = isSecure();
3323
+ const shouldOpenDeeplink = secure && !showInstallModal;
3324
+ if (!shouldOpenDeeplink) {
3325
+ return;
3326
+ }
3327
+ const storedSessionRequest = yield (_a2 = __privateGet(this, _transport2)) == null ? void 0 : _a2.getStoredPendingSessionRequest();
3328
+ if (!storedSessionRequest) {
3329
+ return;
3330
+ }
3331
+ const connectionRequest = {
3332
+ sessionRequest: storedSessionRequest,
3333
+ metadata: {
3334
+ dapp: this.options.dapp,
3335
+ sdk: { version: getVersion(), platform: getPlatformType() }
3336
+ }
3337
+ };
3338
+ const deeplink = this.options.ui.factory.createConnectionDeeplink(connectionRequest);
3339
+ const universalLink = this.options.ui.factory.createConnectionUniversalLink(connectionRequest);
3340
+ if ((_b = this.options.mobile) == null ? void 0 : _b.preferredOpenLink) {
3341
+ this.options.mobile.preferredOpenLink(deeplink, "_self");
3342
+ } else {
3343
+ openDeeplink(this.options, deeplink, universalLink);
3344
+ }
3345
+ });
3346
+ };
3046
3347
  var MetaMaskConnectMultichain = _MetaMaskConnectMultichain;
3047
3348
 
3048
3349
  // src/store/index.ts