@metamask/connect-multichain 0.6.0 → 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 (39) hide show
  1. package/CHANGELOG.md +15 -1
  2. package/README.md +21 -19
  3. package/dist/browser/es/connect-multichain.d.mts +2 -0
  4. package/dist/browser/es/connect-multichain.mjs +38 -7
  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 +2 -0
  8. package/dist/browser/iife/connect-multichain.js +128 -83
  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 +2 -0
  12. package/dist/browser/umd/connect-multichain.js +37 -6
  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 +2 -0
  16. package/dist/node/cjs/connect-multichain.js +37 -6
  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 +2 -0
  20. package/dist/node/es/connect-multichain.mjs +38 -7
  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 +2 -0
  24. package/dist/react-native/es/connect-multichain.mjs +38 -7
  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/types.d.ts +2 -0
  28. package/dist/src/domain/multichain/types.d.ts.map +1 -1
  29. package/dist/src/multichain/transports/multichainApiClientWrapper/index.d.ts.map +1 -1
  30. package/dist/src/multichain/transports/multichainApiClientWrapper/index.js +0 -1
  31. package/dist/src/multichain/transports/multichainApiClientWrapper/index.js.map +1 -1
  32. package/dist/src/multichain/transports/mwp/index.d.ts.map +1 -1
  33. package/dist/src/multichain/transports/mwp/index.js +11 -6
  34. package/dist/src/multichain/transports/mwp/index.js.map +1 -1
  35. package/dist/src/multichain/utils/index.d.ts.map +1 -1
  36. package/dist/src/multichain/utils/index.js +37 -0
  37. package/dist/src/multichain/utils/index.js.map +1 -1
  38. package/dist/types/connect-multichain.d.ts +2 -0
  39. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.7.0]
11
+
12
+ ### Changed
13
+
14
+ - Correct README documentation across `connect-solana`, `connect-evm`, and `connect-multichain` to match actual API behaviour. ([#194](https://github.com/MetaMask/connect-monorepo/pull/194))
15
+ - Redact logs ([#191](https://github.com/MetaMask/connect-monorepo/pull/191]))
16
+ - Pin eciesjs to exact version 0.4.17 ([#188](https://github.com/MetaMask/connect-monorepo/pull/188))
17
+
18
+ ### Fixed
19
+
20
+ - Fix uncaught exception in `parseWalletError` when the wallet returns error codes outside the EIP-1193 provider range (1000–4999), such as standard JSON-RPC codes like `-32603` (Internal error). This prevented Solana request rejections from being handled gracefully. ([#189](https://github.com/MetaMask/connect-monorepo/pull/189))
21
+
10
22
  ## [0.6.0]
11
23
 
12
24
  ### Added
@@ -15,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
15
27
 
16
28
  ### Changed
17
29
 
30
+ - Normalize non-http(s) dapp URLs to valid https URLs on React Native to prevent RPC middleware crashes ([#190](https://github.com/MetaMask/connect-monorepo/pull/190))
18
31
  - **BREAKING** `createMultichainClient()` now returns a singleton. Any incoming constructor params on subsequent calls to `createMultichainClient()` will be applied to the existing singleton instance except for the `dapp`, `storage`, and `ui.factory` param options. ([#157](https://github.com/MetaMask/connect-monorepo/pull/157))
19
32
  - **BREAKING** `ConnectMultichain.openDeeplinkIfNeeded()` is renamed to `openSimpleDeeplinkIfNeeded()` ([#176](https://github.com/MetaMask/connect-monorepo/pull/176))
20
33
  - `ConnectMultichain.connect()` now throws an `'Existing connection is pending. Please check your MetaMask Mobile app to continue.'` error if there is already an pending connection attempt. Previously it would abort that ongoing connection in favor of a new one. ([#157](https://github.com/MetaMask/connect-monorepo/pull/157))
@@ -157,7 +170,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
157
170
 
158
171
  - Initial release
159
172
 
160
- [Unreleased]: https://github.com/MetaMask/connect-monorepo/compare/@metamask/connect-multichain@0.6.0...HEAD
173
+ [Unreleased]: https://github.com/MetaMask/connect-monorepo/compare/@metamask/connect-multichain@0.7.0...HEAD
174
+ [0.7.0]: https://github.com/MetaMask/connect-monorepo/compare/@metamask/connect-multichain@0.6.0...@metamask/connect-multichain@0.7.0
161
175
  [0.6.0]: https://github.com/MetaMask/connect-monorepo/compare/@metamask/connect-multichain@0.5.3...@metamask/connect-multichain@0.6.0
162
176
  [0.5.3]: https://github.com/MetaMask/connect-monorepo/compare/@metamask/connect-multichain@0.5.2...@metamask/connect-multichain@0.5.3
163
177
  [0.5.2]: https://github.com/MetaMask/connect-monorepo/compare/@metamask/connect-multichain@0.5.1...@metamask/connect-multichain@0.5.2
package/README.md CHANGED
@@ -134,26 +134,28 @@ This package is written in TypeScript and includes full type definitions. No add
134
134
 
135
135
  Factory function to create a new Multichain SDK instance.
136
136
 
137
+ > **Singleton:** `createMultichainClient` returns a single shared instance per global context. Calling it a second time with different options will merge the new `api.supportedNetworks`, `ui.*`, `mobile.*`, `transport.extensionId`, and `debug` values into the existing instance rather than creating a new one. The `dapp` value is never overwritten on subsequent calls.
138
+
137
139
  #### Parameters
138
140
 
139
- | Option | Type | Required | Description |
140
- | --------------------------- | --------------------------------------------- | -------- | ---------------------------------------------- |
141
- | `dapp.name` | `string` | Yes | Name of your dApp |
142
- | `api.supportedNetworks` | `RpcUrlsMap` | Yes | Map of CAIP chain IDs to RPC URLs |
143
- | `dapp.url` | `string` | No | URL of your dApp |
144
- | `dapp.iconUrl` | `string` | No | Icon URL for your dApp |
145
- | `dapp.base64Icon` | `string` | No | Base64-encoded icon (alternative to iconUrl) |
146
- | `storage` | `StoreClient` | No | Custom storage adapter |
147
- | `ui.factory` | `BaseModalFactory` | No | Custom modal factory |
148
- | `ui.headless` | `boolean` | No | Run without UI (for custom QR implementations) |
149
- | `ui.preferExtension` | `boolean` | No | Prefer browser extension (default: true) |
150
- | `ui.showInstallModal` | `boolean` | No | Show installation modal |
151
- | `mobile.preferredOpenLink` | `(deeplink: string, target?: string) => void` | No | Custom deeplink handler |
152
- | `mobile.useDeeplink` | `boolean` | No | Use `metamask://` instead of universal links |
153
- | `analytics.integrationType` | `string` | No | Integration type for analytics |
154
- | `transport.extensionId` | `string` | No | Custom extension ID |
155
- | `transport.onNotification` | `(notification: unknown) => void` | No | Notification handler |
156
- | `debug` | `boolean` | No | Enable debug logging |
141
+ | Option | Type | Required | Description |
142
+ | --------------------------- | --------------------------------------------- | -------- | ----------------------------------------------------------------------------- |
143
+ | `dapp.name` | `string` | Yes | Name of your dApp |
144
+ | `api.supportedNetworks` | `RpcUrlsMap` | Yes | Map of [CAIP-2 chain IDs](https://chainagnostic.org/CAIPs/caip-2) to RPC URLs |
145
+ | `dapp.url` | `string` | No | URL of your dApp |
146
+ | `dapp.iconUrl` | `string` | No | Icon URL for your dApp |
147
+ | `dapp.base64Icon` | `string` | No | Base64-encoded icon (alternative to iconUrl) |
148
+ | `storage` | `StoreClient` | No | Custom storage adapter |
149
+ | `ui.factory` | `BaseModalFactory` | No | Custom modal factory |
150
+ | `ui.headless` | `boolean` | No | Run without UI (for custom QR implementations) |
151
+ | `ui.preferExtension` | `boolean` | No | Prefer browser extension (default: true) |
152
+ | `ui.showInstallModal` | `boolean` | No | Show installation modal |
153
+ | `mobile.preferredOpenLink` | `(deeplink: string, target?: string) => void` | No | Custom deeplink handler |
154
+ | `mobile.useDeeplink` | `boolean` | No | Use `metamask://` instead of universal links |
155
+ | `analytics.integrationType` | `string` | No | Integration type for analytics |
156
+ | `transport.extensionId` | `string` | No | Custom extension ID |
157
+ | `transport.onNotification` | `(notification: unknown) => void` | No | Notification handler |
158
+ | `debug` | `boolean` | No | Enable debug logging |
157
159
 
158
160
  #### Returns
159
161
 
@@ -347,7 +349,7 @@ Generates Infura RPC URLs for common networks keyed by CAIP Chain ID.
347
349
 
348
350
  **Returns**
349
351
 
350
- A map of hex chain IDs to Infura RPC URLs. See https://docs.metamask.io/services
352
+ A map of [CAIP-2 chain IDs](https://chainagnostic.org/CAIPs/caip-2) to Infura RPC URLs. See https://docs.metamask.io/services
351
353
 
352
354
  ```typescript
353
355
  import { getInfuraRpcUrls } from '@metamask/connect-multichain';
@@ -369,6 +369,8 @@ declare function hasExtension(): Promise<boolean>;
369
369
  type DappSettings = {
370
370
  name: string;
371
371
  url?: string;
372
+ /** The original non-http(s) URL before normalization on React Native platforms */
373
+ nativeScheme?: string;
372
374
  } & ({
373
375
  iconUrl?: string;
374
376
  } | {
@@ -781,6 +781,21 @@ function getOptionalScopes(scopes) {
781
781
  {}
782
782
  );
783
783
  }
784
+ function normalizeNativeUrl(url) {
785
+ var _a3;
786
+ const httpPattern = /^https?:\/\//u;
787
+ if (httpPattern.test(url)) {
788
+ return void 0;
789
+ }
790
+ const schemeMatch = url.match(/^([^:]*):\/\//u);
791
+ const rawScheme = (_a3 = schemeMatch == null ? void 0 : schemeMatch[1]) != null ? _a3 : url;
792
+ const sanitized = rawScheme.toLowerCase().replace(/[^a-z0-9-]/gu, "-").replace(/^-+|-+$/gu, "");
793
+ const subdomain = (sanitized || "unknown").slice(0, 63).replace(/-+$/u, "");
794
+ return {
795
+ url: `https://${subdomain}.rn.dapp.local`,
796
+ nativeScheme: url
797
+ };
798
+ }
784
799
  function setupDappMetadata(options) {
785
800
  var _a3, _b;
786
801
  const platform = getPlatformType();
@@ -796,6 +811,18 @@ function setupDappMetadata(options) {
796
811
  if (!((_b = options.dapp) == null ? void 0 : _b.url)) {
797
812
  throw new Error("You must provide dapp url");
798
813
  }
814
+ if (platform === "react-native" /* ReactNative */ && options.dapp.url) {
815
+ const normalized = normalizeNativeUrl(options.dapp.url);
816
+ if (normalized) {
817
+ console.info(
818
+ `Normalizing dapp URL for React Native: "${options.dapp.url}" -> "${normalized.url}"`
819
+ );
820
+ options.dapp = __spreadProps(__spreadValues({}, options.dapp), {
821
+ url: normalized.url,
822
+ nativeScheme: normalized.nativeScheme
823
+ });
824
+ }
825
+ }
799
826
  const BASE_64_ICON_MAX_LENGTH = 163400;
800
827
  const urlPattern = /^(http|https):\/\/[^\s]*$/u;
801
828
  if (options.dapp) {
@@ -1878,7 +1905,6 @@ _notificationCallbacks2 = new WeakMap();
1878
1905
  _MultichainApiClientWrapperTransport_instances = new WeakSet();
1879
1906
  walletCreateSession_fn = function(request) {
1880
1907
  return __async(this, null, function* () {
1881
- console.log("\u{1F4DA} #walletCreateSession", request);
1882
1908
  const createSessionParams = request.params;
1883
1909
  const scopes = Object.keys(__spreadValues(__spreadValues({}, createSessionParams.optionalScopes), createSessionParams.requiredScopes));
1884
1910
  const scopeAccounts = [];
@@ -1959,7 +1985,7 @@ import { SessionStore } from "@metamask/mobile-wallet-protocol-core";
1959
1985
  import {
1960
1986
  TransportTimeoutError
1961
1987
  } from "@metamask/multichain-api-client";
1962
- import { providerErrors as providerErrors2, rpcErrors } from "@metamask/rpc-errors";
1988
+ import { JsonRpcError, providerErrors as providerErrors2, rpcErrors } from "@metamask/rpc-errors";
1963
1989
 
1964
1990
  // src/multichain/transports/constants.ts
1965
1991
  var MULTICHAIN_PROVIDER_STREAM_NAME = "metamask-multichain-provider";
@@ -2062,10 +2088,11 @@ var MWPTransport = class {
2062
2088
  parseWalletError(errorPayload) {
2063
2089
  const errorData = errorPayload;
2064
2090
  if (typeof errorData.code === "number" && typeof errorData.message === "string") {
2065
- return providerErrors2.custom({
2066
- code: errorData.code,
2067
- message: errorData.message
2068
- });
2091
+ const { code, message: message2 } = errorData;
2092
+ if (code >= 1e3 && code <= 4999) {
2093
+ return providerErrors2.custom({ code, message: message2 });
2094
+ }
2095
+ return new JsonRpcError(code, message2);
2069
2096
  }
2070
2097
  const message = errorPayload instanceof Error ? errorPayload.message : JSON.stringify(errorPayload);
2071
2098
  return rpcErrors.internal({ message });
@@ -2229,7 +2256,11 @@ var MWPTransport = class {
2229
2256
  const { dappClient } = this;
2230
2257
  const session = yield this.getActiveSession();
2231
2258
  if (session) {
2232
- logger("active session found", session);
2259
+ logger("active session found", {
2260
+ id: session.id,
2261
+ channel: session.channel,
2262
+ expiresAt: session.expiresAt
2263
+ });
2233
2264
  }
2234
2265
  const storedSessionRequestBeforeConnectionAttempt = yield this.getStoredPendingSessionRequest();
2235
2266
  let timeout;