@dynamic-labs-sdk/metamask 0.0.0 → 1.5.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.
- package/README.md +19 -0
- package/dist/clearMetaMaskSessionStorage/clearMetaMaskSessionStorage.d.ts +10 -0
- package/dist/clearMetaMaskSessionStorage/clearMetaMaskSessionStorage.d.ts.map +1 -0
- package/dist/clearMetaMaskSessionStorage/index.d.ts +2 -0
- package/dist/clearMetaMaskSessionStorage/index.d.ts.map +1 -0
- package/dist/connectWithMetaMaskUri/connectWithMetaMaskUri.d.ts +30 -0
- package/dist/connectWithMetaMaskUri/connectWithMetaMaskUri.d.ts.map +1 -0
- package/dist/connectWithMetaMaskUri/index.d.ts +3 -0
- package/dist/connectWithMetaMaskUri/index.d.ts.map +1 -0
- package/dist/errors/MetaMaskDisplayUriMissingError/MetaMaskDisplayUriMissingError.d.ts +5 -0
- package/dist/errors/MetaMaskDisplayUriMissingError/MetaMaskDisplayUriMissingError.d.ts.map +1 -0
- package/dist/errors/MetaMaskDisplayUriMissingError/index.d.ts +2 -0
- package/dist/errors/MetaMaskDisplayUriMissingError/index.d.ts.map +1 -0
- package/dist/errors/MetaMaskWalletNotConnectedError/MetaMaskWalletNotConnectedError.d.ts +5 -0
- package/dist/errors/MetaMaskWalletNotConnectedError/MetaMaskWalletNotConnectedError.d.ts.map +1 -0
- package/dist/errors/MetaMaskWalletNotConnectedError/index.d.ts +2 -0
- package/dist/errors/MetaMaskWalletNotConnectedError/index.d.ts.map +1 -0
- package/dist/exports/index.d.ts +8 -0
- package/dist/exports/index.d.ts.map +1 -0
- package/dist/getMetaMaskExtensionWalletProviderKey/getMetaMaskExtensionWalletProviderKey.d.ts +19 -0
- package/dist/getMetaMaskExtensionWalletProviderKey/getMetaMaskExtensionWalletProviderKey.d.ts.map +1 -0
- package/dist/getMetaMaskExtensionWalletProviderKey/index.d.ts +2 -0
- package/dist/getMetaMaskExtensionWalletProviderKey/index.d.ts.map +1 -0
- package/dist/index.cjs +157 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.esm.js +153 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/metamask.types.d.ts +23 -0
- package/dist/metamask.types.d.ts.map +1 -0
- package/dist/tsconfig.lib.tsbuildinfo +1 -0
- package/package.json +36 -1
package/README.md
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# @dynamic-labs-sdk/metamask
|
|
2
|
+
|
|
3
|
+
Chain-agnostic primitives for integrating the
|
|
4
|
+
[MetaMask SDK](https://docs.metamask.io/sdk/) (`@metamask/connect-multichain`
|
|
5
|
+
and its chain-specific facades such as `@metamask/connect-evm`) with the
|
|
6
|
+
Dynamic JS SDK.
|
|
7
|
+
|
|
8
|
+
This package is intended to be consumed by Dynamic's chain-specific
|
|
9
|
+
packages (`@dynamic-labs-sdk/evm`, `@dynamic-labs-sdk/solana`, …) and
|
|
10
|
+
exposes the building blocks they share — the extension-installed
|
|
11
|
+
guard, the IndexedDB session reset, the connect orchestration that
|
|
12
|
+
returns a `{ approval, uri }` pair, and a thin `MetaMaskController`
|
|
13
|
+
interface that chain-specific glue implements on top of the
|
|
14
|
+
chain-specific MetaMask SDK.
|
|
15
|
+
|
|
16
|
+
Application code should usually import from a chain-specific
|
|
17
|
+
sub-entrypoint instead, e.g. `@dynamic-labs-sdk/evm/metamask`, which
|
|
18
|
+
re-exports a chain-bound `connectWithMetaMaskEvm` /
|
|
19
|
+
`isMetaMaskExtensionInstalled` etc.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deletes the MetaMask SDK's IndexedDB session storage so the next connect call
|
|
3
|
+
* emits a fresh `display_uri` synchronously instead of spending the SDK's
|
|
4
|
+
* 10-second resume timeout reviving a dead pairing. Safe in SSR (no-op) and
|
|
5
|
+
* when the DB is held open by another tab (resolves on `blocked`).
|
|
6
|
+
*
|
|
7
|
+
* @not-instrumented
|
|
8
|
+
*/
|
|
9
|
+
export declare const clearMetaMaskSessionStorage: () => Promise<void>;
|
|
10
|
+
//# sourceMappingURL=clearMetaMaskSessionStorage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clearMetaMaskSessionStorage.d.ts","sourceRoot":"","sources":["../../src/clearMetaMaskSessionStorage/clearMetaMaskSessionStorage.ts"],"names":[],"mappings":"AAMA;;;;;;;GAOG;AACH,eAAO,MAAM,2BAA2B,QAAO,OAAO,CAAC,IAAI,CAsB1D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/clearMetaMaskSessionStorage/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Chain, DynamicClient, WalletProviderUriConnectionResult } from '@dynamic-labs-sdk/client';
|
|
2
|
+
import type { WalletProvider } from '@dynamic-labs-sdk/client/core';
|
|
3
|
+
import type { MetaMaskController } from '../metamask.types';
|
|
4
|
+
export type ConnectWithMetaMaskUriParams = {
|
|
5
|
+
/** Whether to add the connected wallet account to the Dynamic client. Defaults to `true`. */
|
|
6
|
+
addToDynamicWalletAccounts?: boolean;
|
|
7
|
+
/** Chain being connected; used to scope the extension-installed lookup. */
|
|
8
|
+
chain: Chain;
|
|
9
|
+
/** Returns the chain-specific `MetaMaskController` that drives the pairing. */
|
|
10
|
+
getController: (client: DynamicClient) => Promise<MetaMaskController>;
|
|
11
|
+
/**
|
|
12
|
+
* Builds the chain-specific `WalletProvider` AFTER the pairing has been
|
|
13
|
+
* approved. Must NOT include a `connect` method — the provider is registered
|
|
14
|
+
* purely for signing routing and would otherwise leak into the wallet picker.
|
|
15
|
+
*/
|
|
16
|
+
walletProviderBuilder: (client: DynamicClient) => Promise<WalletProvider>;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Drives a MetaMask SDK pairing for any chain and returns `{ approval, uri }`
|
|
20
|
+
* so consumers can render the QR / hand the URI to a deeplink. Logs an
|
|
21
|
+
* advisory warning when the extension is already announced for the chain —
|
|
22
|
+
* pairing still proceeds, but the consumer is told which announced provider
|
|
23
|
+
* key to route through for the best UX. Builds and registers the chain-
|
|
24
|
+
* specific wallet provider only after pairing is approved; the provider
|
|
25
|
+
* therefore never appears in the wallet picker (no `connect` method).
|
|
26
|
+
*
|
|
27
|
+
* @not-instrumented
|
|
28
|
+
*/
|
|
29
|
+
export declare const connectWithMetaMaskUri: ({ addToDynamicWalletAccounts, chain, getController, walletProviderBuilder, }: ConnectWithMetaMaskUriParams, client?: DynamicClient) => Promise<WalletProviderUriConnectionResult>;
|
|
30
|
+
//# sourceMappingURL=connectWithMetaMaskUri.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectWithMetaMaskUri.d.ts","sourceRoot":"","sources":["../../src/connectWithMetaMaskUri/connectWithMetaMaskUri.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,KAAK,EACL,aAAa,EAEb,iCAAiC,EAClC,MAAM,0BAA0B,CAAC;AAElC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAapE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D,MAAM,MAAM,4BAA4B,GAAG;IACzC,6FAA6F;IAC7F,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,2EAA2E;IAC3E,KAAK,EAAE,KAAK,CAAC;IACb,+EAA+E;IAC/E,aAAa,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACtE;;;;OAIG;IACH,qBAAqB,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;CAC3E,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,sBAAsB,iFAM9B,4BAA4B,WACvB,aAAa,KACpB,OAAO,CAAC,iCAAiC,CAmF3C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/connectWithMetaMaskUri/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,YAAY,EAAE,4BAA4B,EAAE,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MetaMaskDisplayUriMissingError.d.ts","sourceRoot":"","sources":["../../../src/errors/MetaMaskDisplayUriMissingError/MetaMaskDisplayUriMissingError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,qBAAa,8BAA+B,SAAQ,SAAS;;CAW5D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/errors/MetaMaskDisplayUriMissingError/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,kCAAkC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MetaMaskWalletNotConnectedError.d.ts","sourceRoot":"","sources":["../../../src/errors/MetaMaskWalletNotConnectedError/MetaMaskWalletNotConnectedError.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,qBAAa,+BAAgC,SAAQ,SAAS;;CAW7D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/errors/MetaMaskWalletNotConnectedError/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,+BAA+B,EAAE,MAAM,mCAAmC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { clearMetaMaskSessionStorage } from '../clearMetaMaskSessionStorage';
|
|
2
|
+
export { connectWithMetaMaskUri } from '../connectWithMetaMaskUri';
|
|
3
|
+
export type { ConnectWithMetaMaskUriParams } from '../connectWithMetaMaskUri';
|
|
4
|
+
export { MetaMaskDisplayUriMissingError } from '../errors/MetaMaskDisplayUriMissingError';
|
|
5
|
+
export { MetaMaskWalletNotConnectedError } from '../errors/MetaMaskWalletNotConnectedError';
|
|
6
|
+
export { getMetaMaskExtensionWalletProviderKey } from '../getMetaMaskExtensionWalletProviderKey';
|
|
7
|
+
export type { DisplayUriListener, MetaMaskController, } from '../metamask.types';
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/exports/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAC;AAC7E,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,YAAY,EAAE,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAAE,8BAA8B,EAAE,MAAM,0CAA0C,CAAC;AAC1F,OAAO,EAAE,+BAA+B,EAAE,MAAM,2CAA2C,CAAC;AAC5F,OAAO,EAAE,qCAAqC,EAAE,MAAM,0CAA0C,CAAC;AACjG,YAAY,EACV,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';
|
|
2
|
+
type GetMetaMaskExtensionWalletProviderKeyParams = {
|
|
3
|
+
/** Chain to scope the lookup to. */
|
|
4
|
+
chain: Chain;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Returns the wallet provider key of the MetaMask browser extension announced
|
|
8
|
+
* for the given chain (EIP-6963 on EVM, Wallet Standard on Solana), or
|
|
9
|
+
* `undefined` when none is announced. Matches on normalized display name to
|
|
10
|
+
* cover MetaMask, Flask, and other variants. Synchronous and safe to call from
|
|
11
|
+
* a React render. Pass the returned key to `connectWithWalletProvider` to route
|
|
12
|
+
* the connection through the announced provider; fall back to the chain's
|
|
13
|
+
* `connectWithMetaMaskUri<Chain>` helper when `undefined`.
|
|
14
|
+
*
|
|
15
|
+
* @not-instrumented
|
|
16
|
+
*/
|
|
17
|
+
export declare const getMetaMaskExtensionWalletProviderKey: ({ chain }: GetMetaMaskExtensionWalletProviderKeyParams, client?: DynamicClient) => string | undefined;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=getMetaMaskExtensionWalletProviderKey.d.ts.map
|
package/dist/getMetaMaskExtensionWalletProviderKey/getMetaMaskExtensionWalletProviderKey.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getMetaMaskExtensionWalletProviderKey.d.ts","sourceRoot":"","sources":["../../src/getMetaMaskExtensionWalletProviderKey/getMetaMaskExtensionWalletProviderKey.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AASrE,KAAK,2CAA2C,GAAG;IACjD,oCAAoC;IACpC,KAAK,EAAE,KAAK,CAAC;CACd,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qCAAqC,cACrC,2CAA2C,WAC9C,aAAa,KACpB,MAAM,GAAG,SAaX,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/getMetaMaskExtensionWalletProviderKey/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qCAAqC,EAAE,MAAM,yCAAyC,CAAC"}
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
let _dynamic_labs_sdk_assert_package_version = require("@dynamic-labs-sdk/assert-package-version");
|
|
2
|
+
let _dynamic_labs_sdk_client = require("@dynamic-labs-sdk/client");
|
|
3
|
+
let _dynamic_labs_sdk_client_core = require("@dynamic-labs-sdk/client/core");
|
|
4
|
+
let _dynamic_labs_sdk_api_core = require("@dynamic-labs/sdk-api-core");
|
|
5
|
+
|
|
6
|
+
//#region package.json
|
|
7
|
+
var name = "@dynamic-labs-sdk/metamask";
|
|
8
|
+
var version = "1.5.0";
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/clearMetaMaskSessionStorage/clearMetaMaskSessionStorage.ts
|
|
12
|
+
const METAMASK_SDK_IDB_NAME = "mmconnect-kv-store";
|
|
13
|
+
/**
|
|
14
|
+
* Deletes the MetaMask SDK's IndexedDB session storage so the next connect call
|
|
15
|
+
* emits a fresh `display_uri` synchronously instead of spending the SDK's
|
|
16
|
+
* 10-second resume timeout reviving a dead pairing. Safe in SSR (no-op) and
|
|
17
|
+
* when the DB is held open by another tab (resolves on `blocked`).
|
|
18
|
+
*
|
|
19
|
+
* @not-instrumented
|
|
20
|
+
*/
|
|
21
|
+
const clearMetaMaskSessionStorage = () => {
|
|
22
|
+
if (typeof indexedDB === "undefined") return Promise.resolve();
|
|
23
|
+
return new Promise((resolve) => {
|
|
24
|
+
try {
|
|
25
|
+
const request = indexedDB.deleteDatabase(METAMASK_SDK_IDB_NAME);
|
|
26
|
+
request.onsuccess = () => resolve();
|
|
27
|
+
request.onerror = () => resolve();
|
|
28
|
+
request.onblocked = () => resolve();
|
|
29
|
+
} catch {
|
|
30
|
+
resolve();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/errors/MetaMaskDisplayUriMissingError/MetaMaskDisplayUriMissingError.ts
|
|
37
|
+
var MetaMaskDisplayUriMissingError = class extends _dynamic_labs_sdk_client.BaseError {
|
|
38
|
+
constructor() {
|
|
39
|
+
super({
|
|
40
|
+
cause: null,
|
|
41
|
+
code: "metamask_display_uri_missing",
|
|
42
|
+
docsUrl: null,
|
|
43
|
+
name: "MetaMaskDisplayUriMissingError",
|
|
44
|
+
shortMessage: "MetaMask SDK completed the connection without emitting a display_uri. The connect helper requires the SDK to produce a pairing URI. Please reach out to Dynamic about this error."
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/getMetaMaskExtensionWalletProviderKey/getMetaMaskExtensionWalletProviderKey.ts
|
|
51
|
+
const METAMASK_NAME_NEEDLE = "metamask";
|
|
52
|
+
/**
|
|
53
|
+
* Returns the wallet provider key of the MetaMask browser extension announced
|
|
54
|
+
* for the given chain (EIP-6963 on EVM, Wallet Standard on Solana), or
|
|
55
|
+
* `undefined` when none is announced. Matches on normalized display name to
|
|
56
|
+
* cover MetaMask, Flask, and other variants. Synchronous and safe to call from
|
|
57
|
+
* a React render. Pass the returned key to `connectWithWalletProvider` to route
|
|
58
|
+
* the connection through the announced provider; fall back to the chain's
|
|
59
|
+
* `connectWithMetaMaskUri<Chain>` helper when `undefined`.
|
|
60
|
+
*
|
|
61
|
+
* @not-instrumented
|
|
62
|
+
*/
|
|
63
|
+
const getMetaMaskExtensionWalletProviderKey = ({ chain }, client = (0, _dynamic_labs_sdk_client_core.getDefaultClient)()) => {
|
|
64
|
+
return (0, _dynamic_labs_sdk_client_core.getWalletProviderRegistry)(client).listProviders().find((provider) => provider.chain === chain && provider.walletProviderType === _dynamic_labs_sdk_api_core.WalletProviderEnum.BrowserExtension && provider.metadata.displayName?.toLowerCase().includes(METAMASK_NAME_NEEDLE))?.key;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/connectWithMetaMaskUri/connectWithMetaMaskUri.ts
|
|
69
|
+
/**
|
|
70
|
+
* Drives a MetaMask SDK pairing for any chain and returns `{ approval, uri }`
|
|
71
|
+
* so consumers can render the QR / hand the URI to a deeplink. Logs an
|
|
72
|
+
* advisory warning when the extension is already announced for the chain —
|
|
73
|
+
* pairing still proceeds, but the consumer is told which announced provider
|
|
74
|
+
* key to route through for the best UX. Builds and registers the chain-
|
|
75
|
+
* specific wallet provider only after pairing is approved; the provider
|
|
76
|
+
* therefore never appears in the wallet picker (no `connect` method).
|
|
77
|
+
*
|
|
78
|
+
* @not-instrumented
|
|
79
|
+
*/
|
|
80
|
+
const connectWithMetaMaskUri = async ({ addToDynamicWalletAccounts = true, chain, getController, walletProviderBuilder }, client = (0, _dynamic_labs_sdk_client_core.getDefaultClient)()) => {
|
|
81
|
+
const announcedKey = getMetaMaskExtensionWalletProviderKey({ chain }, client);
|
|
82
|
+
if (announcedKey !== void 0) (0, _dynamic_labs_sdk_client_core.getCore)(client).logger.warn(`[metamask] MetaMask extension is announced for ${chain} as wallet provider "${announcedKey}"; proceeding with URI pairing. Consider connectWithWalletProvider({ walletProviderKey: "${announcedKey}" }) for the best user experience.`);
|
|
83
|
+
const controller = await getController(client);
|
|
84
|
+
const uriDeferred = (0, _dynamic_labs_sdk_client_core.createDeferredPromise)();
|
|
85
|
+
const unsubscribe = controller.onDisplayUri((displayUri) => {
|
|
86
|
+
uriDeferred.resolve(displayUri);
|
|
87
|
+
});
|
|
88
|
+
const connectPromise = controller.connect();
|
|
89
|
+
connectPromise.then(() => {
|
|
90
|
+
uriDeferred.reject(new MetaMaskDisplayUriMissingError());
|
|
91
|
+
}).catch((error) => {
|
|
92
|
+
uriDeferred.reject(error);
|
|
93
|
+
});
|
|
94
|
+
let uri;
|
|
95
|
+
try {
|
|
96
|
+
uri = await uriDeferred.promise;
|
|
97
|
+
} finally {
|
|
98
|
+
unsubscribe();
|
|
99
|
+
}
|
|
100
|
+
const approval = async () => {
|
|
101
|
+
await connectPromise;
|
|
102
|
+
const walletProvider = await walletProviderBuilder(client);
|
|
103
|
+
(0, _dynamic_labs_sdk_client_core.getWalletProviderRegistry)(client).register({
|
|
104
|
+
priority: _dynamic_labs_sdk_client_core.WalletProviderPriority.WALLET_SDK,
|
|
105
|
+
walletProvider
|
|
106
|
+
});
|
|
107
|
+
const { addresses } = await walletProvider.getConnectedAddresses();
|
|
108
|
+
const mainAddress = addresses[0];
|
|
109
|
+
if (mainAddress === void 0) throw new _dynamic_labs_sdk_client.NoAddressFoundError();
|
|
110
|
+
return { walletAccounts: (0, _dynamic_labs_sdk_client_core.reconcileWalletAccountsAgainstClient)({
|
|
111
|
+
addToDynamicWalletAccounts,
|
|
112
|
+
walletAccounts: [{
|
|
113
|
+
address: mainAddress,
|
|
114
|
+
chain: walletProvider.chain,
|
|
115
|
+
id: (0, _dynamic_labs_sdk_client_core.formatWalletAccountId)({
|
|
116
|
+
address: mainAddress,
|
|
117
|
+
chain: walletProvider.chain,
|
|
118
|
+
walletProviderKey: walletProvider.key
|
|
119
|
+
}),
|
|
120
|
+
lastSelectedAt: null,
|
|
121
|
+
verifiedCredentialId: null,
|
|
122
|
+
walletProviderKey: walletProvider.key
|
|
123
|
+
}],
|
|
124
|
+
walletProviderKey: walletProvider.key
|
|
125
|
+
}, client) };
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
approval,
|
|
129
|
+
uri
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/errors/MetaMaskWalletNotConnectedError/MetaMaskWalletNotConnectedError.ts
|
|
135
|
+
var MetaMaskWalletNotConnectedError = class extends _dynamic_labs_sdk_client.BaseError {
|
|
136
|
+
constructor() {
|
|
137
|
+
super({
|
|
138
|
+
cause: null,
|
|
139
|
+
code: "metamask_wallet_not_connected",
|
|
140
|
+
docsUrl: null,
|
|
141
|
+
name: "MetaMaskWalletNotConnectedError",
|
|
142
|
+
shortMessage: "MetaMask SDK has no connected wallet account. Complete the URI pairing (await the connect approval) before building the MetaMask wallet provider."
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region src/exports/index.ts
|
|
149
|
+
(0, _dynamic_labs_sdk_assert_package_version.assertPackageVersion)(name, version);
|
|
150
|
+
|
|
151
|
+
//#endregion
|
|
152
|
+
exports.MetaMaskDisplayUriMissingError = MetaMaskDisplayUriMissingError;
|
|
153
|
+
exports.MetaMaskWalletNotConnectedError = MetaMaskWalletNotConnectedError;
|
|
154
|
+
exports.clearMetaMaskSessionStorage = clearMetaMaskSessionStorage;
|
|
155
|
+
exports.connectWithMetaMaskUri = connectWithMetaMaskUri;
|
|
156
|
+
exports.getMetaMaskExtensionWalletProviderKey = getMetaMaskExtensionWalletProviderKey;
|
|
157
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["BaseError","WalletProviderEnum","uri: string","WalletProviderPriority","NoAddressFoundError","BaseError"],"sources":["../package.json","../src/clearMetaMaskSessionStorage/clearMetaMaskSessionStorage.ts","../src/errors/MetaMaskDisplayUriMissingError/MetaMaskDisplayUriMissingError.ts","../src/getMetaMaskExtensionWalletProviderKey/getMetaMaskExtensionWalletProviderKey.ts","../src/connectWithMetaMaskUri/connectWithMetaMaskUri.ts","../src/errors/MetaMaskWalletNotConnectedError/MetaMaskWalletNotConnectedError.ts","../src/exports/index.ts"],"sourcesContent":["","// MetaMask SDK persists session state in this IndexedDB database.\n// Hardcoded inside `@metamask/connect-multichain` (the SDK shared by\n// every chain-specific connect-* facade) as `${DB_NAME}${dbNameSuffix}`\n// → `mmconnect` + `-kv-store` on web.\nconst METAMASK_SDK_IDB_NAME = 'mmconnect-kv-store';\n\n/**\n * Deletes the MetaMask SDK's IndexedDB session storage so the next connect call\n * emits a fresh `display_uri` synchronously instead of spending the SDK's\n * 10-second resume timeout reviving a dead pairing. Safe in SSR (no-op) and\n * when the DB is held open by another tab (resolves on `blocked`).\n *\n * @not-instrumented\n */\nexport const clearMetaMaskSessionStorage = (): Promise<void> => {\n if (typeof indexedDB === 'undefined') {\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve) => {\n try {\n const request = indexedDB.deleteDatabase(METAMASK_SDK_IDB_NAME);\n request.onsuccess = () => resolve();\n // `onerror` / `onblocked` fire when a concurrent tab holds the\n // DB open. We still resolve so the consumer's connect flow is\n // not stalled indefinitely; the next tab close drops the lock\n // and subsequent runs reach the empty database. The Promise\n // executor already ignores subsequent resolve calls, so no\n // extra guard is needed when multiple lifecycle events fire on\n // the same request.\n request.onerror = () => resolve();\n request.onblocked = () => resolve();\n } catch {\n resolve();\n }\n });\n};\n","import { BaseError } from '@dynamic-labs-sdk/client';\n\nexport class MetaMaskDisplayUriMissingError extends BaseError {\n constructor() {\n super({\n cause: null,\n code: 'metamask_display_uri_missing',\n docsUrl: null,\n name: 'MetaMaskDisplayUriMissingError',\n shortMessage:\n 'MetaMask SDK completed the connection without emitting a display_uri. The connect helper requires the SDK to produce a pairing URI. Please reach out to Dynamic about this error.',\n });\n }\n}\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport {\n getDefaultClient,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\nimport { WalletProviderEnum } from '@dynamic-labs/sdk-api-core';\n\nconst METAMASK_NAME_NEEDLE = 'metamask';\n\ntype GetMetaMaskExtensionWalletProviderKeyParams = {\n /** Chain to scope the lookup to. */\n chain: Chain;\n};\n\n/**\n * Returns the wallet provider key of the MetaMask browser extension announced\n * for the given chain (EIP-6963 on EVM, Wallet Standard on Solana), or\n * `undefined` when none is announced. Matches on normalized display name to\n * cover MetaMask, Flask, and other variants. Synchronous and safe to call from\n * a React render. Pass the returned key to `connectWithWalletProvider` to route\n * the connection through the announced provider; fall back to the chain's\n * `connectWithMetaMaskUri<Chain>` helper when `undefined`.\n *\n * @not-instrumented\n */\nexport const getMetaMaskExtensionWalletProviderKey = (\n { chain }: GetMetaMaskExtensionWalletProviderKeyParams,\n client: DynamicClient = getDefaultClient()\n): string | undefined => {\n const providers = getWalletProviderRegistry(client).listProviders();\n\n const match = providers.find(\n (provider) =>\n provider.chain === chain &&\n provider.walletProviderType === WalletProviderEnum.BrowserExtension &&\n provider.metadata.displayName\n ?.toLowerCase()\n .includes(METAMASK_NAME_NEEDLE)\n );\n\n return match?.key;\n};\n","import type {\n Chain,\n DynamicClient,\n WalletAccount,\n WalletProviderUriConnectionResult,\n} from '@dynamic-labs-sdk/client';\nimport { NoAddressFoundError } from '@dynamic-labs-sdk/client';\nimport type { WalletProvider } from '@dynamic-labs-sdk/client/core';\nimport {\n WalletProviderPriority,\n createDeferredPromise,\n formatWalletAccountId,\n getCore,\n getDefaultClient,\n getWalletProviderRegistry,\n reconcileWalletAccountsAgainstClient,\n} from '@dynamic-labs-sdk/client/core';\n\nimport { MetaMaskDisplayUriMissingError } from '../errors/MetaMaskDisplayUriMissingError';\nimport { getMetaMaskExtensionWalletProviderKey } from '../getMetaMaskExtensionWalletProviderKey';\nimport type { MetaMaskController } from '../metamask.types';\n\nexport type ConnectWithMetaMaskUriParams = {\n /** Whether to add the connected wallet account to the Dynamic client. Defaults to `true`. */\n addToDynamicWalletAccounts?: boolean;\n /** Chain being connected; used to scope the extension-installed lookup. */\n chain: Chain;\n /** Returns the chain-specific `MetaMaskController` that drives the pairing. */\n getController: (client: DynamicClient) => Promise<MetaMaskController>;\n /**\n * Builds the chain-specific `WalletProvider` AFTER the pairing has been\n * approved. Must NOT include a `connect` method — the provider is registered\n * purely for signing routing and would otherwise leak into the wallet picker.\n */\n walletProviderBuilder: (client: DynamicClient) => Promise<WalletProvider>;\n};\n\n/**\n * Drives a MetaMask SDK pairing for any chain and returns `{ approval, uri }`\n * so consumers can render the QR / hand the URI to a deeplink. Logs an\n * advisory warning when the extension is already announced for the chain —\n * pairing still proceeds, but the consumer is told which announced provider\n * key to route through for the best UX. Builds and registers the chain-\n * specific wallet provider only after pairing is approved; the provider\n * therefore never appears in the wallet picker (no `connect` method).\n *\n * @not-instrumented\n */\nexport const connectWithMetaMaskUri = async (\n {\n addToDynamicWalletAccounts = true,\n chain,\n getController,\n walletProviderBuilder,\n }: ConnectWithMetaMaskUriParams,\n client: DynamicClient = getDefaultClient()\n): Promise<WalletProviderUriConnectionResult> => {\n const announcedKey = getMetaMaskExtensionWalletProviderKey({ chain }, client);\n\n if (announcedKey !== undefined) {\n getCore(client).logger.warn(\n `[metamask] MetaMask extension is announced for ${chain} as wallet provider \"${announcedKey}\"; proceeding with URI pairing. Consider connectWithWalletProvider({ walletProviderKey: \"${announcedKey}\" }) for the best user experience.`\n );\n }\n\n const controller = await getController(client);\n\n const uriDeferred = createDeferredPromise<string>();\n\n const unsubscribe = controller.onDisplayUri((displayUri) => {\n uriDeferred.resolve(displayUri);\n });\n\n const connectPromise = controller.connect();\n\n // If `connect` settles before a `display_uri` is emitted, no URI was made\n // available and the pairing is unusable. Reject the deferred so the caller\n // surfaces `MetaMaskDisplayUriMissingError` (or the underlying failure).\n connectPromise\n .then(() => {\n uriDeferred.reject(new MetaMaskDisplayUriMissingError());\n })\n .catch((error: unknown) => {\n uriDeferred.reject(error);\n });\n\n let uri: string;\n try {\n uri = await uriDeferred.promise;\n } finally {\n unsubscribe();\n }\n\n const approval = async (): Promise<{ walletAccounts: WalletAccount[] }> => {\n await connectPromise;\n\n const walletProvider = await walletProviderBuilder(client);\n\n getWalletProviderRegistry(client).register({\n priority: WalletProviderPriority.WALLET_SDK,\n walletProvider,\n });\n\n const { addresses } = await walletProvider.getConnectedAddresses();\n\n // MetaMask SDK exposes a single active address per pairing (same model as\n // EIP-1193 `eth_accounts`); we only materialize the first one.\n const mainAddress = addresses[0];\n\n if (mainAddress === undefined) {\n throw new NoAddressFoundError();\n }\n\n const walletAccount: WalletAccount = {\n address: mainAddress,\n chain: walletProvider.chain,\n id: formatWalletAccountId({\n address: mainAddress,\n chain: walletProvider.chain,\n walletProviderKey: walletProvider.key,\n }),\n lastSelectedAt: null,\n verifiedCredentialId: null,\n walletProviderKey: walletProvider.key,\n };\n\n const walletAccounts = reconcileWalletAccountsAgainstClient(\n {\n addToDynamicWalletAccounts,\n walletAccounts: [walletAccount],\n walletProviderKey: walletProvider.key,\n },\n client\n );\n\n return { walletAccounts };\n };\n\n return { approval, uri };\n};\n","import { BaseError } from '@dynamic-labs-sdk/client';\n\nexport class MetaMaskWalletNotConnectedError extends BaseError {\n constructor() {\n super({\n cause: null,\n code: 'metamask_wallet_not_connected',\n docsUrl: null,\n name: 'MetaMaskWalletNotConnectedError',\n shortMessage:\n 'MetaMask SDK has no connected wallet account. Complete the URI pairing (await the connect approval) before building the MetaMask wallet provider.',\n });\n }\n}\n","import { assertPackageVersion } from '@dynamic-labs-sdk/assert-package-version';\n\nimport { name, version } from '../../package.json';\n\nassertPackageVersion(name, version);\n\nexport { clearMetaMaskSessionStorage } from '../clearMetaMaskSessionStorage';\nexport { connectWithMetaMaskUri } from '../connectWithMetaMaskUri';\nexport type { ConnectWithMetaMaskUriParams } from '../connectWithMetaMaskUri';\nexport { MetaMaskDisplayUriMissingError } from '../errors/MetaMaskDisplayUriMissingError';\nexport { MetaMaskWalletNotConnectedError } from '../errors/MetaMaskWalletNotConnectedError';\nexport { getMetaMaskExtensionWalletProviderKey } from '../getMetaMaskExtensionWalletProviderKey';\nexport type {\n DisplayUriListener,\n MetaMaskController,\n} from '../metamask.types';\n"],"mappings":";;;;;;;;;;;ACIA,MAAM,wBAAwB;;;;;;;;;AAU9B,MAAa,oCAAmD;AAC9D,KAAI,OAAO,cAAc,YACvB,QAAO,QAAQ,SAAS;AAG1B,QAAO,IAAI,SAAe,YAAY;AACpC,MAAI;GACF,MAAM,UAAU,UAAU,eAAe,sBAAsB;AAC/D,WAAQ,kBAAkB,SAAS;AAQnC,WAAQ,gBAAgB,SAAS;AACjC,WAAQ,kBAAkB,SAAS;UAC7B;AACN,YAAS;;GAEX;;;;;ACjCJ,IAAa,iCAAb,cAAoDA,mCAAU;CAC5D,cAAc;AACZ,QAAM;GACJ,OAAO;GACP,MAAM;GACN,SAAS;GACT,MAAM;GACN,cACE;GACH,CAAC;;;;;;ACJN,MAAM,uBAAuB;;;;;;;;;;;;AAkB7B,MAAa,yCACX,EAAE,SACF,8DAA0C,KACnB;AAYvB,qEAX4C,OAAO,CAAC,eAAe,CAE3C,MACrB,aACC,SAAS,UAAU,SACnB,SAAS,uBAAuBC,8CAAmB,oBACnD,SAAS,SAAS,aACd,aAAa,CACd,SAAS,qBAAqB,CACpC,EAEa;;;;;;;;;;;;;;;;ACQhB,MAAa,yBAAyB,OACpC,EACE,6BAA6B,MAC7B,OACA,eACA,yBAEF,8DAA0C,KACK;CAC/C,MAAM,eAAe,sCAAsC,EAAE,OAAO,EAAE,OAAO;AAE7E,KAAI,iBAAiB,OACnB,4CAAQ,OAAO,CAAC,OAAO,KACrB,kDAAkD,MAAM,uBAAuB,aAAa,2FAA2F,aAAa,oCACrM;CAGH,MAAM,aAAa,MAAM,cAAc,OAAO;CAE9C,MAAM,wEAA6C;CAEnD,MAAM,cAAc,WAAW,cAAc,eAAe;AAC1D,cAAY,QAAQ,WAAW;GAC/B;CAEF,MAAM,iBAAiB,WAAW,SAAS;AAK3C,gBACG,WAAW;AACV,cAAY,OAAO,IAAI,gCAAgC,CAAC;GACxD,CACD,OAAO,UAAmB;AACzB,cAAY,OAAO,MAAM;GACzB;CAEJ,IAAIC;AACJ,KAAI;AACF,QAAM,MAAM,YAAY;WAChB;AACR,eAAa;;CAGf,MAAM,WAAW,YAA0D;AACzE,QAAM;EAEN,MAAM,iBAAiB,MAAM,sBAAsB,OAAO;AAE1D,+DAA0B,OAAO,CAAC,SAAS;GACzC,UAAUC,qDAAuB;GACjC;GACD,CAAC;EAEF,MAAM,EAAE,cAAc,MAAM,eAAe,uBAAuB;EAIlE,MAAM,cAAc,UAAU;AAE9B,MAAI,gBAAgB,OAClB,OAAM,IAAIC,8CAAqB;AAyBjC,SAAO,EAAE,wFARP;GACE;GACA,gBAAgB,CAhBiB;IACnC,SAAS;IACT,OAAO,eAAe;IACtB,6DAA0B;KACxB,SAAS;KACT,OAAO,eAAe;KACtB,mBAAmB,eAAe;KACnC,CAAC;IACF,gBAAgB;IAChB,sBAAsB;IACtB,mBAAmB,eAAe;IACnC,CAKkC;GAC/B,mBAAmB,eAAe;GACnC,EACD,OACD,EAEwB;;AAG3B,QAAO;EAAE;EAAU;EAAK;;;;;ACxI1B,IAAa,kCAAb,cAAqDC,mCAAU;CAC7D,cAAc;AACZ,QAAM;GACJ,OAAO;GACP,MAAM;GACN,SAAS;GACT,MAAM;GACN,cACE;GACH,CAAC;;;;;;mECPe,MAAM,QAAQ"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { assertPackageVersion } from "@dynamic-labs-sdk/assert-package-version";
|
|
2
|
+
import { BaseError, NoAddressFoundError } from "@dynamic-labs-sdk/client";
|
|
3
|
+
import { WalletProviderPriority, createDeferredPromise, formatWalletAccountId, getCore, getDefaultClient, getWalletProviderRegistry, reconcileWalletAccountsAgainstClient } from "@dynamic-labs-sdk/client/core";
|
|
4
|
+
import { WalletProviderEnum } from "@dynamic-labs/sdk-api-core";
|
|
5
|
+
|
|
6
|
+
//#region package.json
|
|
7
|
+
var name = "@dynamic-labs-sdk/metamask";
|
|
8
|
+
var version = "1.5.0";
|
|
9
|
+
|
|
10
|
+
//#endregion
|
|
11
|
+
//#region src/clearMetaMaskSessionStorage/clearMetaMaskSessionStorage.ts
|
|
12
|
+
const METAMASK_SDK_IDB_NAME = "mmconnect-kv-store";
|
|
13
|
+
/**
|
|
14
|
+
* Deletes the MetaMask SDK's IndexedDB session storage so the next connect call
|
|
15
|
+
* emits a fresh `display_uri` synchronously instead of spending the SDK's
|
|
16
|
+
* 10-second resume timeout reviving a dead pairing. Safe in SSR (no-op) and
|
|
17
|
+
* when the DB is held open by another tab (resolves on `blocked`).
|
|
18
|
+
*
|
|
19
|
+
* @not-instrumented
|
|
20
|
+
*/
|
|
21
|
+
const clearMetaMaskSessionStorage = () => {
|
|
22
|
+
if (typeof indexedDB === "undefined") return Promise.resolve();
|
|
23
|
+
return new Promise((resolve) => {
|
|
24
|
+
try {
|
|
25
|
+
const request = indexedDB.deleteDatabase(METAMASK_SDK_IDB_NAME);
|
|
26
|
+
request.onsuccess = () => resolve();
|
|
27
|
+
request.onerror = () => resolve();
|
|
28
|
+
request.onblocked = () => resolve();
|
|
29
|
+
} catch {
|
|
30
|
+
resolve();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/errors/MetaMaskDisplayUriMissingError/MetaMaskDisplayUriMissingError.ts
|
|
37
|
+
var MetaMaskDisplayUriMissingError = class extends BaseError {
|
|
38
|
+
constructor() {
|
|
39
|
+
super({
|
|
40
|
+
cause: null,
|
|
41
|
+
code: "metamask_display_uri_missing",
|
|
42
|
+
docsUrl: null,
|
|
43
|
+
name: "MetaMaskDisplayUriMissingError",
|
|
44
|
+
shortMessage: "MetaMask SDK completed the connection without emitting a display_uri. The connect helper requires the SDK to produce a pairing URI. Please reach out to Dynamic about this error."
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/getMetaMaskExtensionWalletProviderKey/getMetaMaskExtensionWalletProviderKey.ts
|
|
51
|
+
const METAMASK_NAME_NEEDLE = "metamask";
|
|
52
|
+
/**
|
|
53
|
+
* Returns the wallet provider key of the MetaMask browser extension announced
|
|
54
|
+
* for the given chain (EIP-6963 on EVM, Wallet Standard on Solana), or
|
|
55
|
+
* `undefined` when none is announced. Matches on normalized display name to
|
|
56
|
+
* cover MetaMask, Flask, and other variants. Synchronous and safe to call from
|
|
57
|
+
* a React render. Pass the returned key to `connectWithWalletProvider` to route
|
|
58
|
+
* the connection through the announced provider; fall back to the chain's
|
|
59
|
+
* `connectWithMetaMaskUri<Chain>` helper when `undefined`.
|
|
60
|
+
*
|
|
61
|
+
* @not-instrumented
|
|
62
|
+
*/
|
|
63
|
+
const getMetaMaskExtensionWalletProviderKey = ({ chain }, client = getDefaultClient()) => {
|
|
64
|
+
return getWalletProviderRegistry(client).listProviders().find((provider) => provider.chain === chain && provider.walletProviderType === WalletProviderEnum.BrowserExtension && provider.metadata.displayName?.toLowerCase().includes(METAMASK_NAME_NEEDLE))?.key;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/connectWithMetaMaskUri/connectWithMetaMaskUri.ts
|
|
69
|
+
/**
|
|
70
|
+
* Drives a MetaMask SDK pairing for any chain and returns `{ approval, uri }`
|
|
71
|
+
* so consumers can render the QR / hand the URI to a deeplink. Logs an
|
|
72
|
+
* advisory warning when the extension is already announced for the chain —
|
|
73
|
+
* pairing still proceeds, but the consumer is told which announced provider
|
|
74
|
+
* key to route through for the best UX. Builds and registers the chain-
|
|
75
|
+
* specific wallet provider only after pairing is approved; the provider
|
|
76
|
+
* therefore never appears in the wallet picker (no `connect` method).
|
|
77
|
+
*
|
|
78
|
+
* @not-instrumented
|
|
79
|
+
*/
|
|
80
|
+
const connectWithMetaMaskUri = async ({ addToDynamicWalletAccounts = true, chain, getController, walletProviderBuilder }, client = getDefaultClient()) => {
|
|
81
|
+
const announcedKey = getMetaMaskExtensionWalletProviderKey({ chain }, client);
|
|
82
|
+
if (announcedKey !== void 0) getCore(client).logger.warn(`[metamask] MetaMask extension is announced for ${chain} as wallet provider "${announcedKey}"; proceeding with URI pairing. Consider connectWithWalletProvider({ walletProviderKey: "${announcedKey}" }) for the best user experience.`);
|
|
83
|
+
const controller = await getController(client);
|
|
84
|
+
const uriDeferred = createDeferredPromise();
|
|
85
|
+
const unsubscribe = controller.onDisplayUri((displayUri) => {
|
|
86
|
+
uriDeferred.resolve(displayUri);
|
|
87
|
+
});
|
|
88
|
+
const connectPromise = controller.connect();
|
|
89
|
+
connectPromise.then(() => {
|
|
90
|
+
uriDeferred.reject(new MetaMaskDisplayUriMissingError());
|
|
91
|
+
}).catch((error) => {
|
|
92
|
+
uriDeferred.reject(error);
|
|
93
|
+
});
|
|
94
|
+
let uri;
|
|
95
|
+
try {
|
|
96
|
+
uri = await uriDeferred.promise;
|
|
97
|
+
} finally {
|
|
98
|
+
unsubscribe();
|
|
99
|
+
}
|
|
100
|
+
const approval = async () => {
|
|
101
|
+
await connectPromise;
|
|
102
|
+
const walletProvider = await walletProviderBuilder(client);
|
|
103
|
+
getWalletProviderRegistry(client).register({
|
|
104
|
+
priority: WalletProviderPriority.WALLET_SDK,
|
|
105
|
+
walletProvider
|
|
106
|
+
});
|
|
107
|
+
const { addresses } = await walletProvider.getConnectedAddresses();
|
|
108
|
+
const mainAddress = addresses[0];
|
|
109
|
+
if (mainAddress === void 0) throw new NoAddressFoundError();
|
|
110
|
+
return { walletAccounts: reconcileWalletAccountsAgainstClient({
|
|
111
|
+
addToDynamicWalletAccounts,
|
|
112
|
+
walletAccounts: [{
|
|
113
|
+
address: mainAddress,
|
|
114
|
+
chain: walletProvider.chain,
|
|
115
|
+
id: formatWalletAccountId({
|
|
116
|
+
address: mainAddress,
|
|
117
|
+
chain: walletProvider.chain,
|
|
118
|
+
walletProviderKey: walletProvider.key
|
|
119
|
+
}),
|
|
120
|
+
lastSelectedAt: null,
|
|
121
|
+
verifiedCredentialId: null,
|
|
122
|
+
walletProviderKey: walletProvider.key
|
|
123
|
+
}],
|
|
124
|
+
walletProviderKey: walletProvider.key
|
|
125
|
+
}, client) };
|
|
126
|
+
};
|
|
127
|
+
return {
|
|
128
|
+
approval,
|
|
129
|
+
uri
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/errors/MetaMaskWalletNotConnectedError/MetaMaskWalletNotConnectedError.ts
|
|
135
|
+
var MetaMaskWalletNotConnectedError = class extends BaseError {
|
|
136
|
+
constructor() {
|
|
137
|
+
super({
|
|
138
|
+
cause: null,
|
|
139
|
+
code: "metamask_wallet_not_connected",
|
|
140
|
+
docsUrl: null,
|
|
141
|
+
name: "MetaMaskWalletNotConnectedError",
|
|
142
|
+
shortMessage: "MetaMask SDK has no connected wallet account. Complete the URI pairing (await the connect approval) before building the MetaMask wallet provider."
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
//#endregion
|
|
148
|
+
//#region src/exports/index.ts
|
|
149
|
+
assertPackageVersion(name, version);
|
|
150
|
+
|
|
151
|
+
//#endregion
|
|
152
|
+
export { MetaMaskDisplayUriMissingError, MetaMaskWalletNotConnectedError, clearMetaMaskSessionStorage, connectWithMetaMaskUri, getMetaMaskExtensionWalletProviderKey };
|
|
153
|
+
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.esm.js","names":["uri: string"],"sources":["../package.json","../src/clearMetaMaskSessionStorage/clearMetaMaskSessionStorage.ts","../src/errors/MetaMaskDisplayUriMissingError/MetaMaskDisplayUriMissingError.ts","../src/getMetaMaskExtensionWalletProviderKey/getMetaMaskExtensionWalletProviderKey.ts","../src/connectWithMetaMaskUri/connectWithMetaMaskUri.ts","../src/errors/MetaMaskWalletNotConnectedError/MetaMaskWalletNotConnectedError.ts","../src/exports/index.ts"],"sourcesContent":["","// MetaMask SDK persists session state in this IndexedDB database.\n// Hardcoded inside `@metamask/connect-multichain` (the SDK shared by\n// every chain-specific connect-* facade) as `${DB_NAME}${dbNameSuffix}`\n// → `mmconnect` + `-kv-store` on web.\nconst METAMASK_SDK_IDB_NAME = 'mmconnect-kv-store';\n\n/**\n * Deletes the MetaMask SDK's IndexedDB session storage so the next connect call\n * emits a fresh `display_uri` synchronously instead of spending the SDK's\n * 10-second resume timeout reviving a dead pairing. Safe in SSR (no-op) and\n * when the DB is held open by another tab (resolves on `blocked`).\n *\n * @not-instrumented\n */\nexport const clearMetaMaskSessionStorage = (): Promise<void> => {\n if (typeof indexedDB === 'undefined') {\n return Promise.resolve();\n }\n\n return new Promise<void>((resolve) => {\n try {\n const request = indexedDB.deleteDatabase(METAMASK_SDK_IDB_NAME);\n request.onsuccess = () => resolve();\n // `onerror` / `onblocked` fire when a concurrent tab holds the\n // DB open. We still resolve so the consumer's connect flow is\n // not stalled indefinitely; the next tab close drops the lock\n // and subsequent runs reach the empty database. The Promise\n // executor already ignores subsequent resolve calls, so no\n // extra guard is needed when multiple lifecycle events fire on\n // the same request.\n request.onerror = () => resolve();\n request.onblocked = () => resolve();\n } catch {\n resolve();\n }\n });\n};\n","import { BaseError } from '@dynamic-labs-sdk/client';\n\nexport class MetaMaskDisplayUriMissingError extends BaseError {\n constructor() {\n super({\n cause: null,\n code: 'metamask_display_uri_missing',\n docsUrl: null,\n name: 'MetaMaskDisplayUriMissingError',\n shortMessage:\n 'MetaMask SDK completed the connection without emitting a display_uri. The connect helper requires the SDK to produce a pairing URI. Please reach out to Dynamic about this error.',\n });\n }\n}\n","import type { Chain, DynamicClient } from '@dynamic-labs-sdk/client';\nimport {\n getDefaultClient,\n getWalletProviderRegistry,\n} from '@dynamic-labs-sdk/client/core';\nimport { WalletProviderEnum } from '@dynamic-labs/sdk-api-core';\n\nconst METAMASK_NAME_NEEDLE = 'metamask';\n\ntype GetMetaMaskExtensionWalletProviderKeyParams = {\n /** Chain to scope the lookup to. */\n chain: Chain;\n};\n\n/**\n * Returns the wallet provider key of the MetaMask browser extension announced\n * for the given chain (EIP-6963 on EVM, Wallet Standard on Solana), or\n * `undefined` when none is announced. Matches on normalized display name to\n * cover MetaMask, Flask, and other variants. Synchronous and safe to call from\n * a React render. Pass the returned key to `connectWithWalletProvider` to route\n * the connection through the announced provider; fall back to the chain's\n * `connectWithMetaMaskUri<Chain>` helper when `undefined`.\n *\n * @not-instrumented\n */\nexport const getMetaMaskExtensionWalletProviderKey = (\n { chain }: GetMetaMaskExtensionWalletProviderKeyParams,\n client: DynamicClient = getDefaultClient()\n): string | undefined => {\n const providers = getWalletProviderRegistry(client).listProviders();\n\n const match = providers.find(\n (provider) =>\n provider.chain === chain &&\n provider.walletProviderType === WalletProviderEnum.BrowserExtension &&\n provider.metadata.displayName\n ?.toLowerCase()\n .includes(METAMASK_NAME_NEEDLE)\n );\n\n return match?.key;\n};\n","import type {\n Chain,\n DynamicClient,\n WalletAccount,\n WalletProviderUriConnectionResult,\n} from '@dynamic-labs-sdk/client';\nimport { NoAddressFoundError } from '@dynamic-labs-sdk/client';\nimport type { WalletProvider } from '@dynamic-labs-sdk/client/core';\nimport {\n WalletProviderPriority,\n createDeferredPromise,\n formatWalletAccountId,\n getCore,\n getDefaultClient,\n getWalletProviderRegistry,\n reconcileWalletAccountsAgainstClient,\n} from '@dynamic-labs-sdk/client/core';\n\nimport { MetaMaskDisplayUriMissingError } from '../errors/MetaMaskDisplayUriMissingError';\nimport { getMetaMaskExtensionWalletProviderKey } from '../getMetaMaskExtensionWalletProviderKey';\nimport type { MetaMaskController } from '../metamask.types';\n\nexport type ConnectWithMetaMaskUriParams = {\n /** Whether to add the connected wallet account to the Dynamic client. Defaults to `true`. */\n addToDynamicWalletAccounts?: boolean;\n /** Chain being connected; used to scope the extension-installed lookup. */\n chain: Chain;\n /** Returns the chain-specific `MetaMaskController` that drives the pairing. */\n getController: (client: DynamicClient) => Promise<MetaMaskController>;\n /**\n * Builds the chain-specific `WalletProvider` AFTER the pairing has been\n * approved. Must NOT include a `connect` method — the provider is registered\n * purely for signing routing and would otherwise leak into the wallet picker.\n */\n walletProviderBuilder: (client: DynamicClient) => Promise<WalletProvider>;\n};\n\n/**\n * Drives a MetaMask SDK pairing for any chain and returns `{ approval, uri }`\n * so consumers can render the QR / hand the URI to a deeplink. Logs an\n * advisory warning when the extension is already announced for the chain —\n * pairing still proceeds, but the consumer is told which announced provider\n * key to route through for the best UX. Builds and registers the chain-\n * specific wallet provider only after pairing is approved; the provider\n * therefore never appears in the wallet picker (no `connect` method).\n *\n * @not-instrumented\n */\nexport const connectWithMetaMaskUri = async (\n {\n addToDynamicWalletAccounts = true,\n chain,\n getController,\n walletProviderBuilder,\n }: ConnectWithMetaMaskUriParams,\n client: DynamicClient = getDefaultClient()\n): Promise<WalletProviderUriConnectionResult> => {\n const announcedKey = getMetaMaskExtensionWalletProviderKey({ chain }, client);\n\n if (announcedKey !== undefined) {\n getCore(client).logger.warn(\n `[metamask] MetaMask extension is announced for ${chain} as wallet provider \"${announcedKey}\"; proceeding with URI pairing. Consider connectWithWalletProvider({ walletProviderKey: \"${announcedKey}\" }) for the best user experience.`\n );\n }\n\n const controller = await getController(client);\n\n const uriDeferred = createDeferredPromise<string>();\n\n const unsubscribe = controller.onDisplayUri((displayUri) => {\n uriDeferred.resolve(displayUri);\n });\n\n const connectPromise = controller.connect();\n\n // If `connect` settles before a `display_uri` is emitted, no URI was made\n // available and the pairing is unusable. Reject the deferred so the caller\n // surfaces `MetaMaskDisplayUriMissingError` (or the underlying failure).\n connectPromise\n .then(() => {\n uriDeferred.reject(new MetaMaskDisplayUriMissingError());\n })\n .catch((error: unknown) => {\n uriDeferred.reject(error);\n });\n\n let uri: string;\n try {\n uri = await uriDeferred.promise;\n } finally {\n unsubscribe();\n }\n\n const approval = async (): Promise<{ walletAccounts: WalletAccount[] }> => {\n await connectPromise;\n\n const walletProvider = await walletProviderBuilder(client);\n\n getWalletProviderRegistry(client).register({\n priority: WalletProviderPriority.WALLET_SDK,\n walletProvider,\n });\n\n const { addresses } = await walletProvider.getConnectedAddresses();\n\n // MetaMask SDK exposes a single active address per pairing (same model as\n // EIP-1193 `eth_accounts`); we only materialize the first one.\n const mainAddress = addresses[0];\n\n if (mainAddress === undefined) {\n throw new NoAddressFoundError();\n }\n\n const walletAccount: WalletAccount = {\n address: mainAddress,\n chain: walletProvider.chain,\n id: formatWalletAccountId({\n address: mainAddress,\n chain: walletProvider.chain,\n walletProviderKey: walletProvider.key,\n }),\n lastSelectedAt: null,\n verifiedCredentialId: null,\n walletProviderKey: walletProvider.key,\n };\n\n const walletAccounts = reconcileWalletAccountsAgainstClient(\n {\n addToDynamicWalletAccounts,\n walletAccounts: [walletAccount],\n walletProviderKey: walletProvider.key,\n },\n client\n );\n\n return { walletAccounts };\n };\n\n return { approval, uri };\n};\n","import { BaseError } from '@dynamic-labs-sdk/client';\n\nexport class MetaMaskWalletNotConnectedError extends BaseError {\n constructor() {\n super({\n cause: null,\n code: 'metamask_wallet_not_connected',\n docsUrl: null,\n name: 'MetaMaskWalletNotConnectedError',\n shortMessage:\n 'MetaMask SDK has no connected wallet account. Complete the URI pairing (await the connect approval) before building the MetaMask wallet provider.',\n });\n }\n}\n","import { assertPackageVersion } from '@dynamic-labs-sdk/assert-package-version';\n\nimport { name, version } from '../../package.json';\n\nassertPackageVersion(name, version);\n\nexport { clearMetaMaskSessionStorage } from '../clearMetaMaskSessionStorage';\nexport { connectWithMetaMaskUri } from '../connectWithMetaMaskUri';\nexport type { ConnectWithMetaMaskUriParams } from '../connectWithMetaMaskUri';\nexport { MetaMaskDisplayUriMissingError } from '../errors/MetaMaskDisplayUriMissingError';\nexport { MetaMaskWalletNotConnectedError } from '../errors/MetaMaskWalletNotConnectedError';\nexport { getMetaMaskExtensionWalletProviderKey } from '../getMetaMaskExtensionWalletProviderKey';\nexport type {\n DisplayUriListener,\n MetaMaskController,\n} from '../metamask.types';\n"],"mappings":";;;;;;;;;;;ACIA,MAAM,wBAAwB;;;;;;;;;AAU9B,MAAa,oCAAmD;AAC9D,KAAI,OAAO,cAAc,YACvB,QAAO,QAAQ,SAAS;AAG1B,QAAO,IAAI,SAAe,YAAY;AACpC,MAAI;GACF,MAAM,UAAU,UAAU,eAAe,sBAAsB;AAC/D,WAAQ,kBAAkB,SAAS;AAQnC,WAAQ,gBAAgB,SAAS;AACjC,WAAQ,kBAAkB,SAAS;UAC7B;AACN,YAAS;;GAEX;;;;;ACjCJ,IAAa,iCAAb,cAAoD,UAAU;CAC5D,cAAc;AACZ,QAAM;GACJ,OAAO;GACP,MAAM;GACN,SAAS;GACT,MAAM;GACN,cACE;GACH,CAAC;;;;;;ACJN,MAAM,uBAAuB;;;;;;;;;;;;AAkB7B,MAAa,yCACX,EAAE,SACF,SAAwB,kBAAkB,KACnB;AAYvB,QAXkB,0BAA0B,OAAO,CAAC,eAAe,CAE3C,MACrB,aACC,SAAS,UAAU,SACnB,SAAS,uBAAuB,mBAAmB,oBACnD,SAAS,SAAS,aACd,aAAa,CACd,SAAS,qBAAqB,CACpC,EAEa;;;;;;;;;;;;;;;;ACQhB,MAAa,yBAAyB,OACpC,EACE,6BAA6B,MAC7B,OACA,eACA,yBAEF,SAAwB,kBAAkB,KACK;CAC/C,MAAM,eAAe,sCAAsC,EAAE,OAAO,EAAE,OAAO;AAE7E,KAAI,iBAAiB,OACnB,SAAQ,OAAO,CAAC,OAAO,KACrB,kDAAkD,MAAM,uBAAuB,aAAa,2FAA2F,aAAa,oCACrM;CAGH,MAAM,aAAa,MAAM,cAAc,OAAO;CAE9C,MAAM,cAAc,uBAA+B;CAEnD,MAAM,cAAc,WAAW,cAAc,eAAe;AAC1D,cAAY,QAAQ,WAAW;GAC/B;CAEF,MAAM,iBAAiB,WAAW,SAAS;AAK3C,gBACG,WAAW;AACV,cAAY,OAAO,IAAI,gCAAgC,CAAC;GACxD,CACD,OAAO,UAAmB;AACzB,cAAY,OAAO,MAAM;GACzB;CAEJ,IAAIA;AACJ,KAAI;AACF,QAAM,MAAM,YAAY;WAChB;AACR,eAAa;;CAGf,MAAM,WAAW,YAA0D;AACzE,QAAM;EAEN,MAAM,iBAAiB,MAAM,sBAAsB,OAAO;AAE1D,4BAA0B,OAAO,CAAC,SAAS;GACzC,UAAU,uBAAuB;GACjC;GACD,CAAC;EAEF,MAAM,EAAE,cAAc,MAAM,eAAe,uBAAuB;EAIlE,MAAM,cAAc,UAAU;AAE9B,MAAI,gBAAgB,OAClB,OAAM,IAAI,qBAAqB;AAyBjC,SAAO,EAAE,gBATc,qCACrB;GACE;GACA,gBAAgB,CAhBiB;IACnC,SAAS;IACT,OAAO,eAAe;IACtB,IAAI,sBAAsB;KACxB,SAAS;KACT,OAAO,eAAe;KACtB,mBAAmB,eAAe;KACnC,CAAC;IACF,gBAAgB;IAChB,sBAAsB;IACtB,mBAAmB,eAAe;IACnC,CAKkC;GAC/B,mBAAmB,eAAe;GACnC,EACD,OACD,EAEwB;;AAG3B,QAAO;EAAE;EAAU;EAAK;;;;;ACxI1B,IAAa,kCAAb,cAAqD,UAAU;CAC7D,cAAc;AACZ,QAAM;GACJ,OAAO;GACP,MAAM;GACN,SAAS;GACT,MAAM;GACN,cACE;GACH,CAAC;;;;;;ACPN,qBAAqB,MAAM,QAAQ"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Listener invoked with each MetaMask SDK pairing `display_uri` emission. */
|
|
2
|
+
export type DisplayUriListener = (uri: string) => void;
|
|
3
|
+
/**
|
|
4
|
+
* Chain-agnostic surface chain-specific packages adapt their MetaMask SDK
|
|
5
|
+
* instance to (e.g. `@metamask/connect-evm`, `@metamask/connect-solana`).
|
|
6
|
+
* Owns the SDK pairing drive (`connect`) and the cached-`display_uri`
|
|
7
|
+
* bookkeeping (`onDisplayUri` / `getLatestDisplayUri` / `clearCachedDisplayUri`).
|
|
8
|
+
*/
|
|
9
|
+
export type MetaMaskController = {
|
|
10
|
+
/** Drops the cached `display_uri` value without touching the SDK. */
|
|
11
|
+
clearCachedDisplayUri: () => void;
|
|
12
|
+
/**
|
|
13
|
+
* Drives the SDK pairing. Implementations should clear any stale
|
|
14
|
+
* "connecting" state on the underlying SDK first. Resolves once the
|
|
15
|
+
* pairing is approved by the wallet; rejects on rejection / timeout.
|
|
16
|
+
*/
|
|
17
|
+
connect: () => Promise<void>;
|
|
18
|
+
/** Returns the latest URI captured by the SDK's `displayUri` handler, or `undefined`. */
|
|
19
|
+
getLatestDisplayUri: () => string | undefined;
|
|
20
|
+
/** Subscribes to `display_uri` emissions and replays the latest cached URI. Returns an unsubscribe. */
|
|
21
|
+
onDisplayUri: (listener: DisplayUriListener) => () => void;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=metamask.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metamask.types.d.ts","sourceRoot":"","sources":["../src/metamask.types.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,MAAM,MAAM,kBAAkB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;AAEvD;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,qEAAqE;IACrE,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAClC;;;;OAIG;IACH,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,yFAAyF;IACzF,mBAAmB,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IAC9C,uGAAuG;IACvG,YAAY,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,MAAM,IAAI,CAAC;CAC5D,CAAC"}
|