@multiplatform.one/web3 7.24.0 → 7.26.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 +33 -0
- package/dist/cjs/bridge/AuthBridge.cjs +124 -0
- package/dist/cjs/bridge/AuthBridge.native.js +186 -0
- package/dist/cjs/bridge/AuthBridge.native.js.map +1 -0
- package/dist/cjs/bridge/BridgeClient.cjs +12 -9
- package/dist/cjs/bridge/BridgeClient.native.js +17 -12
- package/dist/cjs/bridge/BridgeClient.native.js.map +1 -1
- package/dist/cjs/bridge/BridgeHost.cjs +11 -3
- package/dist/cjs/bridge/BridgeHost.native.js +11 -3
- package/dist/cjs/bridge/BridgeHost.native.js.map +1 -1
- package/dist/cjs/bridge/GpgBridge.cjs +61 -0
- package/dist/cjs/bridge/GpgBridge.native.js +111 -0
- package/dist/cjs/bridge/GpgBridge.native.js.map +1 -0
- package/dist/cjs/bridge/SuiBridge.cjs +51 -0
- package/dist/cjs/bridge/SuiBridge.native.js +99 -0
- package/dist/cjs/bridge/SuiBridge.native.js.map +1 -0
- package/dist/cjs/bridge/authTypes.cjs +28 -0
- package/dist/cjs/bridge/authTypes.native.js +31 -0
- package/dist/cjs/bridge/authTypes.native.js.map +1 -0
- package/dist/cjs/bridge/core.cjs +65 -0
- package/dist/cjs/bridge/core.native.js +68 -0
- package/dist/cjs/bridge/core.native.js.map +1 -0
- package/dist/cjs/bridge/hosting.cjs +91 -0
- package/dist/cjs/bridge/hosting.native.js +117 -0
- package/dist/cjs/bridge/hosting.native.js.map +1 -0
- package/dist/cjs/bridge/index.cjs +3 -17
- package/dist/cjs/bridge/index.native.js +2 -16
- package/dist/cjs/bridge/index.native.js.map +1 -1
- package/dist/cjs/bridge/nativeHost.cjs +91 -0
- package/dist/cjs/bridge/nativeHost.native.js +118 -0
- package/dist/cjs/bridge/nativeHost.native.js.map +1 -0
- package/dist/cjs/bridge/protocol.cjs +30 -1
- package/dist/cjs/bridge/protocol.native.js +147 -1
- package/dist/cjs/bridge/protocol.native.js.map +1 -1
- package/dist/cjs/core/family.cjs +88 -0
- package/dist/cjs/core/family.native.js +115 -0
- package/dist/cjs/core/family.native.js.map +1 -0
- package/dist/cjs/core/index.cjs +41 -0
- package/dist/cjs/core/index.native.js +44 -0
- package/dist/cjs/core/index.native.js.map +1 -0
- package/dist/cjs/core/message.cjs +89 -0
- package/dist/cjs/core/message.native.js +104 -0
- package/dist/cjs/core/message.native.js.map +1 -0
- package/dist/cjs/core/names.cjs +51 -0
- package/dist/cjs/core/names.native.js +95 -0
- package/dist/cjs/core/names.native.js.map +1 -0
- package/dist/cjs/core/react.cjs +48 -0
- package/dist/cjs/core/react.native.js +52 -0
- package/dist/cjs/core/react.native.js.map +1 -0
- package/dist/cjs/core/store.cjs +450 -0
- package/dist/cjs/core/store.native.js +637 -0
- package/dist/cjs/core/store.native.js.map +1 -0
- package/dist/cjs/core/types.cjs +18 -0
- package/dist/cjs/core/types.native.js +21 -0
- package/dist/cjs/core/types.native.js.map +1 -0
- package/dist/cjs/index.cjs +3 -1
- package/dist/cjs/index.native.js +2 -0
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/providers/WalletProvider.cjs +2 -0
- package/dist/cjs/providers/WalletProvider.native.js +123 -90
- package/dist/cjs/providers/WalletProvider.native.js.map +1 -1
- package/dist/cjs/providers/index.cjs +1 -0
- package/dist/cjs/providers/index.native.js +1 -0
- package/dist/cjs/providers/index.native.js.map +1 -1
- package/dist/cjs/providers/native/deepLink.cjs +40 -23
- package/dist/cjs/providers/native/deepLink.native.js +43 -25
- package/dist/cjs/providers/native/deepLink.native.js.map +1 -1
- package/dist/cjs/providers/native/inject.cjs +2 -4
- package/dist/cjs/providers/native/inject.native.js +2 -4
- package/dist/cjs/providers/native/inject.native.js.map +1 -1
- package/dist/cjs/providers/walletBridge.cjs +35 -0
- package/dist/cjs/providers/walletBridge.native.js +38 -0
- package/dist/cjs/providers/walletBridge.native.js.map +1 -0
- package/dist/cjs/providers/walletConfig.native.js.map +1 -1
- package/dist/esm/bridge/AuthBridge.mjs +99 -0
- package/dist/esm/bridge/AuthBridge.mjs.map +1 -0
- package/dist/esm/bridge/AuthBridge.native.js +158 -0
- package/dist/esm/bridge/AuthBridge.native.js.map +1 -0
- package/dist/esm/bridge/BridgeClient.mjs +13 -10
- package/dist/esm/bridge/BridgeClient.mjs.map +1 -1
- package/dist/esm/bridge/BridgeClient.native.js +18 -13
- package/dist/esm/bridge/BridgeClient.native.js.map +1 -1
- package/dist/esm/bridge/BridgeHost.mjs +12 -4
- package/dist/esm/bridge/BridgeHost.mjs.map +1 -1
- package/dist/esm/bridge/BridgeHost.native.js +12 -4
- package/dist/esm/bridge/BridgeHost.native.js.map +1 -1
- package/dist/esm/bridge/GpgBridge.mjs +36 -0
- package/dist/esm/bridge/GpgBridge.mjs.map +1 -0
- package/dist/esm/bridge/GpgBridge.native.js +83 -0
- package/dist/esm/bridge/GpgBridge.native.js.map +1 -0
- package/dist/esm/bridge/SuiBridge.mjs +26 -0
- package/dist/esm/bridge/SuiBridge.mjs.map +1 -0
- package/dist/esm/bridge/SuiBridge.native.js +71 -0
- package/dist/esm/bridge/SuiBridge.native.js.map +1 -0
- package/dist/esm/bridge/authTypes.mjs +3 -0
- package/dist/esm/bridge/authTypes.mjs.map +1 -0
- package/dist/esm/bridge/authTypes.native.js +3 -0
- package/dist/esm/bridge/authTypes.native.js.map +1 -0
- package/dist/esm/bridge/core.mjs +17 -0
- package/dist/esm/bridge/core.mjs.map +1 -0
- package/dist/esm/bridge/core.native.js +17 -0
- package/dist/esm/bridge/core.native.js.map +1 -0
- package/dist/esm/bridge/hosting.mjs +62 -0
- package/dist/esm/bridge/hosting.mjs.map +1 -0
- package/dist/esm/bridge/hosting.native.js +85 -0
- package/dist/esm/bridge/hosting.native.js.map +1 -0
- package/dist/esm/bridge/index.mjs +2 -9
- package/dist/esm/bridge/index.mjs.map +1 -1
- package/dist/esm/bridge/index.native.js +2 -9
- package/dist/esm/bridge/index.native.js.map +1 -1
- package/dist/esm/bridge/nativeHost.mjs +65 -0
- package/dist/esm/bridge/nativeHost.mjs.map +1 -0
- package/dist/esm/bridge/nativeHost.native.js +89 -0
- package/dist/esm/bridge/nativeHost.native.js.map +1 -0
- package/dist/esm/bridge/protocol.mjs +28 -2
- package/dist/esm/bridge/protocol.mjs.map +1 -1
- package/dist/esm/bridge/protocol.native.js +145 -2
- package/dist/esm/bridge/protocol.native.js.map +1 -1
- package/dist/esm/core/family.mjs +62 -0
- package/dist/esm/core/family.mjs.map +1 -0
- package/dist/esm/core/family.native.js +86 -0
- package/dist/esm/core/family.native.js.map +1 -0
- package/dist/esm/core/index.mjs +7 -0
- package/dist/esm/core/index.mjs.map +1 -0
- package/dist/esm/core/index.native.js +7 -0
- package/dist/esm/core/index.native.js.map +1 -0
- package/dist/esm/core/message.mjs +63 -0
- package/dist/esm/core/message.mjs.map +1 -0
- package/dist/esm/core/message.native.js +75 -0
- package/dist/esm/core/message.native.js.map +1 -0
- package/dist/esm/core/names.mjs +25 -0
- package/dist/esm/core/names.mjs.map +1 -0
- package/dist/esm/core/names.native.js +66 -0
- package/dist/esm/core/names.native.js.map +1 -0
- package/dist/esm/core/react.mjs +21 -0
- package/dist/esm/core/react.mjs.map +1 -0
- package/dist/esm/core/react.native.js +22 -0
- package/dist/esm/core/react.native.js.map +1 -0
- package/dist/esm/core/store.mjs +424 -0
- package/dist/esm/core/store.mjs.map +1 -0
- package/dist/esm/core/store.native.js +608 -0
- package/dist/esm/core/store.native.js.map +1 -0
- package/dist/esm/core/types.mjs +2 -0
- package/dist/esm/core/types.mjs.map +1 -0
- package/dist/esm/core/types.native.js +2 -0
- package/dist/esm/core/types.native.js.map +1 -0
- package/dist/esm/index.mjs +3 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +3 -2
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/providers/WalletProvider.mjs +2 -1
- package/dist/esm/providers/WalletProvider.mjs.map +1 -1
- package/dist/esm/providers/WalletProvider.native.js +125 -93
- package/dist/esm/providers/WalletProvider.native.js.map +1 -1
- package/dist/esm/providers/index.mjs +2 -2
- package/dist/esm/providers/index.mjs.map +1 -1
- package/dist/esm/providers/index.native.js +2 -2
- package/dist/esm/providers/index.native.js.map +1 -1
- package/dist/esm/providers/native/deepLink.mjs +36 -24
- package/dist/esm/providers/native/deepLink.mjs.map +1 -1
- package/dist/esm/providers/native/deepLink.native.js +39 -26
- package/dist/esm/providers/native/deepLink.native.js.map +1 -1
- package/dist/esm/providers/native/inject.mjs +1 -3
- package/dist/esm/providers/native/inject.mjs.map +1 -1
- package/dist/esm/providers/native/inject.native.js +1 -3
- package/dist/esm/providers/native/inject.native.js.map +1 -1
- package/dist/esm/providers/walletBridge.mjs +9 -0
- package/dist/esm/providers/walletBridge.mjs.map +1 -0
- package/dist/esm/providers/walletBridge.native.js +9 -0
- package/dist/esm/providers/walletBridge.native.js.map +1 -0
- package/dist/esm/providers/walletConfig.mjs.map +1 -1
- package/dist/esm/providers/walletConfig.native.js.map +1 -1
- package/dist/jsx/bridge/AuthBridge.mjs +99 -0
- package/dist/jsx/bridge/AuthBridge.mjs.map +1 -0
- package/dist/jsx/bridge/AuthBridge.native.js +186 -0
- package/dist/jsx/bridge/AuthBridge.native.js.map +1 -0
- package/dist/jsx/bridge/BridgeClient.mjs +13 -10
- package/dist/jsx/bridge/BridgeClient.mjs.map +1 -1
- package/dist/jsx/bridge/BridgeClient.native.js +17 -12
- package/dist/jsx/bridge/BridgeClient.native.js.map +1 -1
- package/dist/jsx/bridge/BridgeHost.mjs +12 -4
- package/dist/jsx/bridge/BridgeHost.mjs.map +1 -1
- package/dist/jsx/bridge/BridgeHost.native.js +11 -3
- package/dist/jsx/bridge/BridgeHost.native.js.map +1 -1
- package/dist/jsx/bridge/GpgBridge.mjs +36 -0
- package/dist/jsx/bridge/GpgBridge.mjs.map +1 -0
- package/dist/jsx/bridge/GpgBridge.native.js +111 -0
- package/dist/jsx/bridge/GpgBridge.native.js.map +1 -0
- package/dist/jsx/bridge/SuiBridge.mjs +26 -0
- package/dist/jsx/bridge/SuiBridge.mjs.map +1 -0
- package/dist/jsx/bridge/SuiBridge.native.js +99 -0
- package/dist/jsx/bridge/SuiBridge.native.js.map +1 -0
- package/dist/jsx/bridge/authTypes.mjs +3 -0
- package/dist/jsx/bridge/authTypes.mjs.map +1 -0
- package/dist/jsx/bridge/authTypes.native.js +31 -0
- package/dist/jsx/bridge/authTypes.native.js.map +1 -0
- package/dist/jsx/bridge/core.mjs +17 -0
- package/dist/jsx/bridge/core.mjs.map +1 -0
- package/dist/jsx/bridge/core.native.js +68 -0
- package/dist/jsx/bridge/core.native.js.map +1 -0
- package/dist/jsx/bridge/hosting.mjs +62 -0
- package/dist/jsx/bridge/hosting.mjs.map +1 -0
- package/dist/jsx/bridge/hosting.native.js +117 -0
- package/dist/jsx/bridge/hosting.native.js.map +1 -0
- package/dist/jsx/bridge/index.mjs +2 -9
- package/dist/jsx/bridge/index.mjs.map +1 -1
- package/dist/jsx/bridge/index.native.js +2 -16
- package/dist/jsx/bridge/index.native.js.map +1 -1
- package/dist/jsx/bridge/nativeHost.mjs +65 -0
- package/dist/jsx/bridge/nativeHost.mjs.map +1 -0
- package/dist/jsx/bridge/nativeHost.native.js +118 -0
- package/dist/jsx/bridge/nativeHost.native.js.map +1 -0
- package/dist/jsx/bridge/protocol.mjs +28 -2
- package/dist/jsx/bridge/protocol.mjs.map +1 -1
- package/dist/jsx/bridge/protocol.native.js +147 -1
- package/dist/jsx/bridge/protocol.native.js.map +1 -1
- package/dist/jsx/core/family.mjs +62 -0
- package/dist/jsx/core/family.mjs.map +1 -0
- package/dist/jsx/core/family.native.js +115 -0
- package/dist/jsx/core/family.native.js.map +1 -0
- package/dist/jsx/core/index.mjs +7 -0
- package/dist/jsx/core/index.mjs.map +1 -0
- package/dist/jsx/core/index.native.js +44 -0
- package/dist/jsx/core/index.native.js.map +1 -0
- package/dist/jsx/core/message.mjs +63 -0
- package/dist/jsx/core/message.mjs.map +1 -0
- package/dist/jsx/core/message.native.js +104 -0
- package/dist/jsx/core/message.native.js.map +1 -0
- package/dist/jsx/core/names.mjs +25 -0
- package/dist/jsx/core/names.mjs.map +1 -0
- package/dist/jsx/core/names.native.js +95 -0
- package/dist/jsx/core/names.native.js.map +1 -0
- package/dist/jsx/core/react.mjs +21 -0
- package/dist/jsx/core/react.mjs.map +1 -0
- package/dist/jsx/core/react.native.js +52 -0
- package/dist/jsx/core/react.native.js.map +1 -0
- package/dist/jsx/core/store.mjs +424 -0
- package/dist/jsx/core/store.mjs.map +1 -0
- package/dist/jsx/core/store.native.js +637 -0
- package/dist/jsx/core/store.native.js.map +1 -0
- package/dist/jsx/core/types.mjs +2 -0
- package/dist/jsx/core/types.mjs.map +1 -0
- package/dist/jsx/core/types.native.js +21 -0
- package/dist/jsx/core/types.native.js.map +1 -0
- package/dist/jsx/index.js +3 -2
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +3 -2
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +2 -0
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/providers/WalletProvider.mjs +2 -1
- package/dist/jsx/providers/WalletProvider.mjs.map +1 -1
- package/dist/jsx/providers/WalletProvider.native.js +123 -90
- package/dist/jsx/providers/WalletProvider.native.js.map +1 -1
- package/dist/jsx/providers/index.mjs +2 -2
- package/dist/jsx/providers/index.mjs.map +1 -1
- package/dist/jsx/providers/index.native.js +1 -0
- package/dist/jsx/providers/index.native.js.map +1 -1
- package/dist/jsx/providers/native/deepLink.mjs +36 -24
- package/dist/jsx/providers/native/deepLink.mjs.map +1 -1
- package/dist/jsx/providers/native/deepLink.native.js +43 -25
- package/dist/jsx/providers/native/deepLink.native.js.map +1 -1
- package/dist/jsx/providers/native/inject.mjs +1 -3
- package/dist/jsx/providers/native/inject.mjs.map +1 -1
- package/dist/jsx/providers/native/inject.native.js +2 -4
- package/dist/jsx/providers/native/inject.native.js.map +1 -1
- package/dist/jsx/providers/walletBridge.mjs +9 -0
- package/dist/jsx/providers/walletBridge.mjs.map +1 -0
- package/dist/jsx/providers/walletBridge.native.js +38 -0
- package/dist/jsx/providers/walletBridge.native.js.map +1 -0
- package/dist/jsx/providers/walletConfig.mjs.map +1 -1
- package/dist/jsx/providers/walletConfig.native.js.map +1 -1
- package/docs/bridge-protocol.md +485 -0
- package/package.json +14 -6
- package/src/bridge/AuthBridge.ts +146 -0
- package/src/bridge/BridgeClient.spec.ts +12 -0
- package/src/bridge/BridgeClient.ts +15 -10
- package/src/bridge/BridgeHost.spec.ts +20 -4
- package/src/bridge/BridgeHost.ts +16 -5
- package/src/bridge/GpgBridge.ts +49 -0
- package/src/bridge/SuiBridge.ts +34 -0
- package/src/bridge/authTypes.ts +76 -0
- package/src/bridge/core.ts +42 -0
- package/src/bridge/hosting.spec.ts +98 -0
- package/src/bridge/hosting.ts +99 -0
- package/src/bridge/index.ts +1 -8
- package/src/bridge/nativeHost.spec.ts +165 -0
- package/src/bridge/nativeHost.ts +120 -0
- package/src/bridge/protocol.spec.ts +24 -1
- package/src/bridge/protocol.ts +44 -1
- package/src/core/family.spec.ts +117 -0
- package/src/core/family.ts +103 -0
- package/src/core/imports.spec.ts +82 -0
- package/src/core/index.ts +47 -0
- package/src/core/message.spec.ts +178 -0
- package/src/core/message.ts +119 -0
- package/src/core/names.ts +29 -0
- package/src/core/react.spec.tsx +75 -0
- package/src/core/react.ts +34 -0
- package/src/core/store.spec.ts +890 -0
- package/src/core/store.ts +558 -0
- package/src/core/types.ts +96 -0
- package/src/index.ts +6 -0
- package/src/providers/WalletProvider.native.tsx +139 -85
- package/src/providers/WalletProvider.tsx +1 -1
- package/src/providers/index.ts +2 -0
- package/src/providers/native/deepLink.spec.ts +73 -1
- package/src/providers/native/deepLink.ts +76 -28
- package/src/providers/native/inject.ts +1 -9
- package/src/providers/walletBridge.ts +24 -0
- package/src/providers/walletConfig.ts +15 -1
- package/types/bridge/AuthBridge.d.ts +58 -0
- package/types/bridge/AuthBridge.d.ts.map +1 -0
- package/types/bridge/BridgeClient.d.ts +3 -1
- package/types/bridge/BridgeClient.d.ts.map +1 -1
- package/types/bridge/BridgeHost.d.ts +1 -1
- package/types/bridge/BridgeHost.d.ts.map +1 -1
- package/types/bridge/GpgBridge.d.ts +23 -0
- package/types/bridge/GpgBridge.d.ts.map +1 -0
- package/types/bridge/SuiBridge.d.ts +18 -0
- package/types/bridge/SuiBridge.d.ts.map +1 -0
- package/types/bridge/authTypes.d.ts +71 -0
- package/types/bridge/authTypes.d.ts.map +1 -0
- package/types/bridge/core.d.ts +16 -0
- package/types/bridge/core.d.ts.map +1 -0
- package/types/bridge/hosting.d.ts +34 -0
- package/types/bridge/hosting.d.ts.map +1 -0
- package/types/bridge/index.d.ts +1 -8
- package/types/bridge/index.d.ts.map +1 -1
- package/types/bridge/nativeHost.d.ts +55 -0
- package/types/bridge/nativeHost.d.ts.map +1 -0
- package/types/bridge/protocol.d.ts +34 -1
- package/types/bridge/protocol.d.ts.map +1 -1
- package/types/core/family.d.ts +44 -0
- package/types/core/family.d.ts.map +1 -0
- package/types/core/index.d.ts +7 -0
- package/types/core/index.d.ts.map +1 -0
- package/types/core/message.d.ts +44 -0
- package/types/core/message.d.ts.map +1 -0
- package/types/core/names.d.ts +7 -0
- package/types/core/names.d.ts.map +1 -0
- package/types/core/react.d.ts +14 -0
- package/types/core/react.d.ts.map +1 -0
- package/types/core/store.d.ts +64 -0
- package/types/core/store.d.ts.map +1 -0
- package/types/core/types.d.ts +88 -0
- package/types/core/types.d.ts.map +1 -0
- package/types/index.d.ts +2 -1
- package/types/index.d.ts.map +1 -1
- package/types/providers/WalletProvider.d.ts +1 -0
- package/types/providers/WalletProvider.d.ts.map +1 -1
- package/types/providers/WalletProvider.native.d.ts +2 -1
- package/types/providers/WalletProvider.native.d.ts.map +1 -1
- package/types/providers/index.d.ts +1 -1
- package/types/providers/index.d.ts.map +1 -1
- package/types/providers/native/deepLink.d.ts +29 -4
- package/types/providers/native/deepLink.d.ts.map +1 -1
- package/types/providers/native/inject.d.ts +1 -7
- package/types/providers/native/inject.d.ts.map +1 -1
- package/types/providers/walletBridge.d.ts +17 -0
- package/types/providers/walletBridge.d.ts.map +1 -0
- package/types/providers/walletConfig.d.ts +18 -1
- package/types/providers/walletConfig.d.ts.map +1 -1
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
import type { ChainClient } from "../clients/types";
|
|
2
|
+
import { createFamilyRegistry, type FamilyRegistry, type WalletFamily } from "./family";
|
|
3
|
+
import type {
|
|
4
|
+
ConnectionDriver,
|
|
5
|
+
ConnectionState,
|
|
6
|
+
ConnectionStorage,
|
|
7
|
+
DriverAccount,
|
|
8
|
+
DriverConnectOptions,
|
|
9
|
+
DriverState,
|
|
10
|
+
SavedConnection,
|
|
11
|
+
WalletConnector,
|
|
12
|
+
} from "./types";
|
|
13
|
+
|
|
14
|
+
export const defaultConnectionStorageKey = "mpo.web3.connection";
|
|
15
|
+
|
|
16
|
+
export interface ConnectionStoreOptions {
|
|
17
|
+
families: readonly WalletFamily[] | FamilyRegistry;
|
|
18
|
+
/**
|
|
19
|
+
* Where the last connection is remembered. Defaults to localStorage when the
|
|
20
|
+
* platform has one; null keeps nothing, so nothing is restored.
|
|
21
|
+
*/
|
|
22
|
+
storage?: ConnectionStorage | null;
|
|
23
|
+
storageKey?: string;
|
|
24
|
+
/**
|
|
25
|
+
* How long, in milliseconds, a driver's disconnect may take before the store
|
|
26
|
+
* stops waiting for it. Defaults to 10 seconds. Infinity waits for as long
|
|
27
|
+
* as the driver takes; a negative value waits for nothing.
|
|
28
|
+
*/
|
|
29
|
+
closeTimeout?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface FamilyConnector {
|
|
33
|
+
readonly family: string;
|
|
34
|
+
readonly connector: WalletConnector;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Holds the one active wallet connection across every registered family.
|
|
39
|
+
* Only the active family's driver is listened to, so a second driver that
|
|
40
|
+
* reports an account (wagmi restoring on its own, say) changes nothing.
|
|
41
|
+
*/
|
|
42
|
+
export interface ConnectionStore {
|
|
43
|
+
getState(): ConnectionState;
|
|
44
|
+
subscribe(listener: () => void): () => void;
|
|
45
|
+
readonly registry: FamilyRegistry;
|
|
46
|
+
/**
|
|
47
|
+
* Every connectable family's connectors, merged in family order. The same
|
|
48
|
+
* array comes back until the list changes.
|
|
49
|
+
*/
|
|
50
|
+
connectors(): readonly FamilyConnector[];
|
|
51
|
+
/** Called when any family's connector list changes. */
|
|
52
|
+
subscribeConnectors(listener: () => void): () => void;
|
|
53
|
+
/**
|
|
54
|
+
* Connects one family's connector, first closing any other connection.
|
|
55
|
+
* Remembers {family, connectorId} on success.
|
|
56
|
+
*/
|
|
57
|
+
connect(
|
|
58
|
+
family: string,
|
|
59
|
+
connectorId: string,
|
|
60
|
+
options?: DriverConnectOptions,
|
|
61
|
+
): Promise<ConnectionState>;
|
|
62
|
+
/** Closes the active connection and forgets it. */
|
|
63
|
+
disconnect(): Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Restores the remembered connection through its own driver only. Concurrent
|
|
66
|
+
* calls share one attempt; no other driver is asked. A disconnect from the
|
|
67
|
+
* wallet side keeps the record, so a later reconnect() can restore it.
|
|
68
|
+
*/
|
|
69
|
+
reconnect(): Promise<ConnectionState>;
|
|
70
|
+
/**
|
|
71
|
+
* Stops listening to every driver and to this store's listeners, and refuses
|
|
72
|
+
* later connects. It closes nothing: the connection and the attempt live at
|
|
73
|
+
* that moment stay open on their drivers for whatever takes over, such as a
|
|
74
|
+
* store remounted on the same drivers. A late result of an attempt cancelled
|
|
75
|
+
* before destroy() still closes its own connector unless another store holds
|
|
76
|
+
* it through the same driver object; a store on a fresh driver over the same
|
|
77
|
+
* wallet cannot be told apart from this one's leftover.
|
|
78
|
+
*/
|
|
79
|
+
destroy(): void;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const disconnected: ConnectionState = Object.freeze({
|
|
83
|
+
status: "disconnected",
|
|
84
|
+
family: null,
|
|
85
|
+
connector: null,
|
|
86
|
+
address: null,
|
|
87
|
+
chainId: null,
|
|
88
|
+
client: null,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const superseded = () => new Error("wallet connect superseded");
|
|
92
|
+
|
|
93
|
+
function browserStorage(): ConnectionStorage | null {
|
|
94
|
+
try {
|
|
95
|
+
const storage = (globalThis as { localStorage?: ConnectionStorage }).localStorage;
|
|
96
|
+
return storage && typeof storage.getItem === "function" ? storage : null;
|
|
97
|
+
} catch {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function parseSaved(raw: string | null | undefined): SavedConnection | null {
|
|
103
|
+
if (!raw) return null;
|
|
104
|
+
try {
|
|
105
|
+
const value = JSON.parse(raw) as Partial<SavedConnection> | null;
|
|
106
|
+
return typeof value?.family === "string" && typeof value.connectorId === "string"
|
|
107
|
+
? { family: value.family, connectorId: value.connectorId }
|
|
108
|
+
: null;
|
|
109
|
+
} catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const sameConnector = (a: WalletConnector, b: WalletConnector) =>
|
|
115
|
+
a.id === b.id && a.name === b.name && a.icon === b.icon && a.installed === b.installed;
|
|
116
|
+
|
|
117
|
+
/** What each live store holds on a driver that several stores share. */
|
|
118
|
+
const holdersByDriver = new WeakMap<ConnectionDriver, Set<() => readonly string[]>>();
|
|
119
|
+
|
|
120
|
+
export function createConnectionStore(options: ConnectionStoreOptions): ConnectionStore {
|
|
121
|
+
const registry = Array.isArray(options.families)
|
|
122
|
+
? createFamilyRegistry(options.families as readonly WalletFamily[])
|
|
123
|
+
: (options.families as FamilyRegistry);
|
|
124
|
+
const storage = options.storage === undefined ? browserStorage() : options.storage;
|
|
125
|
+
const key = options.storageKey ?? defaultConnectionStorageKey;
|
|
126
|
+
const requestedClose = options.closeTimeout ?? 10_000;
|
|
127
|
+
const closeTimeout = Number.isNaN(requestedClose) ? 10_000 : Math.max(0, requestedClose);
|
|
128
|
+
const drivers = new Map<string, ConnectionDriver>();
|
|
129
|
+
const holders = new Map<ConnectionDriver, () => readonly string[]>();
|
|
130
|
+
const listeners = new Set<() => void>();
|
|
131
|
+
const connectorListeners = new Set<() => void>();
|
|
132
|
+
const connectorWatches = new Map<ConnectionDriver, () => void>();
|
|
133
|
+
const closing = new Map<ConnectionDriver, Promise<void>>();
|
|
134
|
+
const inflight = new Map<ConnectionDriver, Map<string, number>>();
|
|
135
|
+
let state: ConnectionState = disconnected;
|
|
136
|
+
let active: { driver: ConnectionDriver; connectorId: string; unsubscribe: () => void } | null =
|
|
137
|
+
null;
|
|
138
|
+
let pending: { driver: ConnectionDriver; connectorId: string } | null = null;
|
|
139
|
+
let operation = 0;
|
|
140
|
+
let clientRequest = 0;
|
|
141
|
+
let restoring: Promise<ConnectionState> | null = null;
|
|
142
|
+
let connectorSnapshot: readonly FamilyConnector[] = Object.freeze([]);
|
|
143
|
+
let destroyed = false;
|
|
144
|
+
let keptAtDestroy: readonly ({ driver: ConnectionDriver; connectorId: string } | null)[] = [];
|
|
145
|
+
|
|
146
|
+
const set = (next: ConnectionState) => {
|
|
147
|
+
state = next;
|
|
148
|
+
for (const listener of listeners) listener();
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
const watchConnectors = (driver: ConnectionDriver) => {
|
|
152
|
+
if (connectorListeners.size === 0 || connectorWatches.has(driver) || !driver.watchConnectors) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
connectorWatches.set(
|
|
156
|
+
driver,
|
|
157
|
+
driver.watchConnectors(() => {
|
|
158
|
+
for (const listener of connectorListeners) listener();
|
|
159
|
+
}),
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
const unwatchConnectors = () => {
|
|
164
|
+
for (const unwatch of connectorWatches.values()) unwatch();
|
|
165
|
+
connectorWatches.clear();
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const hold = (driver: ConnectionDriver) => {
|
|
169
|
+
if (destroyed || holders.has(driver)) return;
|
|
170
|
+
const held = () =>
|
|
171
|
+
[active, pending].flatMap((entry) => (entry?.driver === driver ? [entry.connectorId] : []));
|
|
172
|
+
holders.set(driver, held);
|
|
173
|
+
let all = holdersByDriver.get(driver);
|
|
174
|
+
if (!all) {
|
|
175
|
+
all = new Set();
|
|
176
|
+
holdersByDriver.set(driver, all);
|
|
177
|
+
}
|
|
178
|
+
all.add(held);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const driverFor = (family: WalletFamily): ConnectionDriver => {
|
|
182
|
+
if (family.connectionless || !family.driver) {
|
|
183
|
+
throw new Error(`wallet family ${family.id} is connectionless; it signs without connecting`);
|
|
184
|
+
}
|
|
185
|
+
let driver = drivers.get(family.id);
|
|
186
|
+
if (!driver) {
|
|
187
|
+
driver = family.driver();
|
|
188
|
+
drivers.set(family.id, driver);
|
|
189
|
+
hold(driver);
|
|
190
|
+
}
|
|
191
|
+
watchConnectors(driver);
|
|
192
|
+
return driver;
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const heldElsewhere = (driver: ConnectionDriver) =>
|
|
196
|
+
[...(holdersByDriver.get(driver) ?? [])]
|
|
197
|
+
.filter((held) => held !== holders.get(driver))
|
|
198
|
+
.flatMap((held) => held());
|
|
199
|
+
|
|
200
|
+
const connectorFor = (driver: ConnectionDriver, id: string): WalletConnector =>
|
|
201
|
+
driver.connectors().find((connector) => connector.id === id) ?? { id, name: id };
|
|
202
|
+
|
|
203
|
+
const save = async (value: SavedConnection | null) => {
|
|
204
|
+
if (!storage) return;
|
|
205
|
+
try {
|
|
206
|
+
if (value) await storage.setItem(key, JSON.stringify(value));
|
|
207
|
+
else await storage.removeItem(key);
|
|
208
|
+
} catch {
|
|
209
|
+
// A storage that refuses writes (private mode, quota) only costs the restore.
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
const load = async (): Promise<SavedConnection | null> => {
|
|
214
|
+
if (!storage) return null;
|
|
215
|
+
try {
|
|
216
|
+
return parseSaved(await storage.getItem(key));
|
|
217
|
+
} catch {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
// Closes run one after another per driver, and a connect or restore on that
|
|
223
|
+
// driver waits for them: a late close would otherwise drop the new connection.
|
|
224
|
+
// Each is bounded by closeTimeout, so unless that is Infinity one wallet that
|
|
225
|
+
// never answers cannot wedge the queue; a close that times out can still land.
|
|
226
|
+
const closeDriver = (driver: ConnectionDriver, connectorId?: string) => {
|
|
227
|
+
const previous = closing.get(driver);
|
|
228
|
+
const run = (async () => {
|
|
229
|
+
await previous;
|
|
230
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
231
|
+
const closed = (async () => driver.disconnect(connectorId))().catch(() => {
|
|
232
|
+
// The wallet may already be gone; the store has let go of it either way.
|
|
233
|
+
});
|
|
234
|
+
if (closeTimeout === Number.POSITIVE_INFINITY) await closed;
|
|
235
|
+
else {
|
|
236
|
+
await Promise.race([
|
|
237
|
+
closed,
|
|
238
|
+
new Promise<void>((resolve) => {
|
|
239
|
+
timer = setTimeout(resolve, Math.min(closeTimeout, 2_147_483_647));
|
|
240
|
+
}),
|
|
241
|
+
]);
|
|
242
|
+
clearTimeout(timer);
|
|
243
|
+
}
|
|
244
|
+
})();
|
|
245
|
+
closing.set(driver, run);
|
|
246
|
+
void run.then(() => {
|
|
247
|
+
if (closing.get(driver) === run) closing.delete(driver);
|
|
248
|
+
});
|
|
249
|
+
return run;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
const release = () => {
|
|
253
|
+
active?.unsubscribe();
|
|
254
|
+
active = null;
|
|
255
|
+
clientRequest++;
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const closeActive = async () => {
|
|
259
|
+
const previous = active;
|
|
260
|
+
release();
|
|
261
|
+
if (previous) await closeDriver(previous.driver);
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
/** A connection nobody uses any more: a superseded result, or one left by a failed attempt. */
|
|
265
|
+
const settleStale = async (
|
|
266
|
+
driver: ConnectionDriver,
|
|
267
|
+
connectorId: string,
|
|
268
|
+
account: DriverAccount | null,
|
|
269
|
+
) => {
|
|
270
|
+
if (!account) return;
|
|
271
|
+
const inUse = [
|
|
272
|
+
...(destroyed ? keptAtDestroy : [active, pending])
|
|
273
|
+
.filter((entry) => entry?.driver === driver)
|
|
274
|
+
.map((entry) => entry?.connectorId),
|
|
275
|
+
...heldElsewhere(driver),
|
|
276
|
+
];
|
|
277
|
+
if (inUse.includes(connectorId)) return;
|
|
278
|
+
// After destroy() the driver may serve a remounted store, so only this connector goes.
|
|
279
|
+
if (inUse.length === 0 && !destroyed) await closeDriver(driver);
|
|
280
|
+
else await closeDriver(driver, connectorId);
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const closeOrphan = async (driver: ConnectionDriver, connectorId: string) => {
|
|
284
|
+
const left = driver.getState();
|
|
285
|
+
if (!left.account) return;
|
|
286
|
+
if (destroyed) {
|
|
287
|
+
if (left.connectorId === connectorId) {
|
|
288
|
+
await settleStale(driver, connectorId, left.account);
|
|
289
|
+
}
|
|
290
|
+
} else if (left.connectorId !== null) {
|
|
291
|
+
await settleStale(driver, left.connectorId, left.account);
|
|
292
|
+
} else if (
|
|
293
|
+
![active, pending].some((entry) => entry?.driver === driver) &&
|
|
294
|
+
heldElsewhere(driver).length === 0
|
|
295
|
+
) {
|
|
296
|
+
await closeDriver(driver);
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Counts a connect or restore in flight on a driver. While one is, the
|
|
302
|
+
* driver reporting its connector is that attempt landing, not the user
|
|
303
|
+
* switching connectors, so the active connection does not follow it.
|
|
304
|
+
*/
|
|
305
|
+
const track = (driver: ConnectionDriver, connectorId: string) => {
|
|
306
|
+
let counts = inflight.get(driver);
|
|
307
|
+
if (!counts) {
|
|
308
|
+
counts = new Map();
|
|
309
|
+
inflight.set(driver, counts);
|
|
310
|
+
}
|
|
311
|
+
counts.set(connectorId, (counts.get(connectorId) ?? 0) + 1);
|
|
312
|
+
return () => {
|
|
313
|
+
const left = (counts.get(connectorId) ?? 1) - 1;
|
|
314
|
+
if (left > 0) counts.set(connectorId, left);
|
|
315
|
+
else counts.delete(connectorId);
|
|
316
|
+
};
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
const clientFor = (driver: ConnectionDriver, driverState: DriverState): ChainClient | null => {
|
|
320
|
+
const request = ++clientRequest;
|
|
321
|
+
let result: ChainClient | null | Promise<ChainClient | null>;
|
|
322
|
+
try {
|
|
323
|
+
result = driver.client?.(driverState) ?? null;
|
|
324
|
+
} catch {
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
if (result === null || typeof (result as Promise<unknown>).then !== "function") {
|
|
328
|
+
return result as ChainClient | null;
|
|
329
|
+
}
|
|
330
|
+
(result as Promise<ChainClient | null>).then(
|
|
331
|
+
(client) => {
|
|
332
|
+
if (request === clientRequest && active?.driver === driver && client) {
|
|
333
|
+
set(Object.freeze({ ...state, client }));
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
() => {},
|
|
337
|
+
);
|
|
338
|
+
return null;
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const activate = (
|
|
342
|
+
family: WalletFamily,
|
|
343
|
+
driver: ConnectionDriver,
|
|
344
|
+
connector: WalletConnector,
|
|
345
|
+
account: DriverAccount,
|
|
346
|
+
) => {
|
|
347
|
+
release();
|
|
348
|
+
const onChange = () => {
|
|
349
|
+
if (active?.driver !== driver) return;
|
|
350
|
+
const driverState = driver.getState();
|
|
351
|
+
if (!driverState.account) {
|
|
352
|
+
if (driverState.status === "connecting" || driverState.status === "reconnecting") return;
|
|
353
|
+
release();
|
|
354
|
+
operation++;
|
|
355
|
+
set(disconnected);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const connectorId = driverState.connectorId ?? active.connectorId;
|
|
359
|
+
if (connectorId !== active.connectorId && inflight.get(driver)?.get(connectorId)) return;
|
|
360
|
+
const chainId = driverState.account.chainId ?? null;
|
|
361
|
+
if (
|
|
362
|
+
connectorId === state.connector?.id &&
|
|
363
|
+
driverState.account.address === state.address &&
|
|
364
|
+
chainId === state.chainId
|
|
365
|
+
) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const nextConnector =
|
|
369
|
+
connectorId === state.connector?.id && state.connector
|
|
370
|
+
? state.connector
|
|
371
|
+
: connectorFor(driver, connectorId);
|
|
372
|
+
if (connectorId !== active.connectorId) {
|
|
373
|
+
active.connectorId = connectorId;
|
|
374
|
+
void save({ family: family.id, connectorId });
|
|
375
|
+
}
|
|
376
|
+
set(
|
|
377
|
+
Object.freeze({
|
|
378
|
+
status: "connected",
|
|
379
|
+
family: family.id,
|
|
380
|
+
connector: nextConnector,
|
|
381
|
+
address: driverState.account.address,
|
|
382
|
+
chainId,
|
|
383
|
+
client: clientFor(driver, { ...driverState, connectorId }),
|
|
384
|
+
}),
|
|
385
|
+
);
|
|
386
|
+
};
|
|
387
|
+
active = { driver, connectorId: connector.id, unsubscribe: driver.subscribe(onChange) };
|
|
388
|
+
set(
|
|
389
|
+
Object.freeze({
|
|
390
|
+
status: "connected",
|
|
391
|
+
family: family.id,
|
|
392
|
+
connector,
|
|
393
|
+
address: account.address,
|
|
394
|
+
chainId: account.chainId ?? null,
|
|
395
|
+
client: clientFor(driver, { status: "connected", connectorId: connector.id, account }),
|
|
396
|
+
}),
|
|
397
|
+
);
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
return {
|
|
401
|
+
registry,
|
|
402
|
+
getState: () => state,
|
|
403
|
+
subscribe(listener) {
|
|
404
|
+
listeners.add(listener);
|
|
405
|
+
return () => {
|
|
406
|
+
listeners.delete(listener);
|
|
407
|
+
};
|
|
408
|
+
},
|
|
409
|
+
connectors() {
|
|
410
|
+
const next: FamilyConnector[] = [];
|
|
411
|
+
for (const family of registry.families) {
|
|
412
|
+
if (family.connectionless) continue;
|
|
413
|
+
for (const connector of driverFor(family).connectors()) {
|
|
414
|
+
next.push({ family: family.id, connector });
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
const unchanged =
|
|
418
|
+
next.length === connectorSnapshot.length &&
|
|
419
|
+
next.every((entry, index) => {
|
|
420
|
+
const previous = connectorSnapshot[index];
|
|
421
|
+
return (
|
|
422
|
+
previous !== undefined &&
|
|
423
|
+
entry.family === previous.family &&
|
|
424
|
+
sameConnector(entry.connector, previous.connector)
|
|
425
|
+
);
|
|
426
|
+
});
|
|
427
|
+
if (!unchanged) connectorSnapshot = Object.freeze(next.map((entry) => Object.freeze(entry)));
|
|
428
|
+
return connectorSnapshot;
|
|
429
|
+
},
|
|
430
|
+
subscribeConnectors(listener) {
|
|
431
|
+
connectorListeners.add(listener);
|
|
432
|
+
for (const family of registry.families) if (!family.connectionless) driverFor(family);
|
|
433
|
+
return () => {
|
|
434
|
+
connectorListeners.delete(listener);
|
|
435
|
+
if (connectorListeners.size === 0) unwatchConnectors();
|
|
436
|
+
};
|
|
437
|
+
},
|
|
438
|
+
async connect(familyName, connectorId, connectOptions) {
|
|
439
|
+
if (destroyed) throw new Error("this connection store was destroyed");
|
|
440
|
+
const family = registry.require(familyName);
|
|
441
|
+
const driver = driverFor(family);
|
|
442
|
+
const connector = connectorFor(driver, connectorId);
|
|
443
|
+
const current = ++operation;
|
|
444
|
+
restoring = null;
|
|
445
|
+
pending = { driver, connectorId };
|
|
446
|
+
const closingActive = closeActive();
|
|
447
|
+
set(Object.freeze({ ...disconnected, status: "connecting", family: family.id, connector }));
|
|
448
|
+
await closingActive;
|
|
449
|
+
if (current === operation) await save(null);
|
|
450
|
+
await closing.get(driver);
|
|
451
|
+
const untrack = track(driver, connectorId);
|
|
452
|
+
let account: DriverAccount;
|
|
453
|
+
let asked = false;
|
|
454
|
+
try {
|
|
455
|
+
try {
|
|
456
|
+
if (current !== operation) throw superseded();
|
|
457
|
+
asked = true;
|
|
458
|
+
account = await driver.connect(connectorId, connectOptions);
|
|
459
|
+
} catch (error) {
|
|
460
|
+
if (current === operation) {
|
|
461
|
+
pending = null;
|
|
462
|
+
set(disconnected);
|
|
463
|
+
}
|
|
464
|
+
// After destroy() the driver may serve another store; what it holds is
|
|
465
|
+
// this attempt's only if this attempt asked for it.
|
|
466
|
+
if (asked || !destroyed) await closeOrphan(driver, connectorId);
|
|
467
|
+
throw error;
|
|
468
|
+
}
|
|
469
|
+
if (current !== operation) {
|
|
470
|
+
await settleStale(driver, connectorId, account);
|
|
471
|
+
throw superseded();
|
|
472
|
+
}
|
|
473
|
+
} finally {
|
|
474
|
+
untrack();
|
|
475
|
+
}
|
|
476
|
+
pending = null;
|
|
477
|
+
activate(family, driver, connector, account);
|
|
478
|
+
await save({ family: family.id, connectorId });
|
|
479
|
+
return state;
|
|
480
|
+
},
|
|
481
|
+
async disconnect() {
|
|
482
|
+
operation++;
|
|
483
|
+
restoring = null;
|
|
484
|
+
pending = null;
|
|
485
|
+
const closingActive = closeActive();
|
|
486
|
+
set(disconnected);
|
|
487
|
+
await save(null);
|
|
488
|
+
await closingActive;
|
|
489
|
+
},
|
|
490
|
+
reconnect() {
|
|
491
|
+
if (restoring) return restoring;
|
|
492
|
+
if (destroyed || state.status !== "disconnected") return Promise.resolve(state);
|
|
493
|
+
const current = ++operation;
|
|
494
|
+
const attempt = (async (): Promise<ConnectionState> => {
|
|
495
|
+
const saved = await load();
|
|
496
|
+
if (current !== operation || !saved) return state;
|
|
497
|
+
const family = registry.get(saved.family);
|
|
498
|
+
if (!family || family.connectionless || !family.driver) return state;
|
|
499
|
+
const driver = driverFor(family);
|
|
500
|
+
const connector = connectorFor(driver, saved.connectorId);
|
|
501
|
+
pending = { driver, connectorId: saved.connectorId };
|
|
502
|
+
set(
|
|
503
|
+
Object.freeze({ ...disconnected, status: "reconnecting", family: family.id, connector }),
|
|
504
|
+
);
|
|
505
|
+
await closing.get(driver);
|
|
506
|
+
const untrack = track(driver, saved.connectorId);
|
|
507
|
+
let account: DriverAccount | null;
|
|
508
|
+
try {
|
|
509
|
+
try {
|
|
510
|
+
if (current !== operation) return state;
|
|
511
|
+
account = await driver.reconnect(saved.connectorId);
|
|
512
|
+
} catch {
|
|
513
|
+
if (current === operation) {
|
|
514
|
+
pending = null;
|
|
515
|
+
set(disconnected);
|
|
516
|
+
}
|
|
517
|
+
await closeOrphan(driver, saved.connectorId);
|
|
518
|
+
return state;
|
|
519
|
+
}
|
|
520
|
+
if (current !== operation) {
|
|
521
|
+
await settleStale(driver, saved.connectorId, account);
|
|
522
|
+
return state;
|
|
523
|
+
}
|
|
524
|
+
} finally {
|
|
525
|
+
untrack();
|
|
526
|
+
}
|
|
527
|
+
pending = null;
|
|
528
|
+
if (!account) {
|
|
529
|
+
set(disconnected);
|
|
530
|
+
await save(null);
|
|
531
|
+
await closeOrphan(driver, saved.connectorId);
|
|
532
|
+
return state;
|
|
533
|
+
}
|
|
534
|
+
activate(family, driver, connector, account);
|
|
535
|
+
return state;
|
|
536
|
+
})();
|
|
537
|
+
restoring = attempt;
|
|
538
|
+
const settled = () => {
|
|
539
|
+
if (restoring === attempt) restoring = null;
|
|
540
|
+
};
|
|
541
|
+
void attempt.then(settled, settled);
|
|
542
|
+
return attempt;
|
|
543
|
+
},
|
|
544
|
+
destroy() {
|
|
545
|
+
if (destroyed) return;
|
|
546
|
+
destroyed = true;
|
|
547
|
+
keptAtDestroy = [active, pending];
|
|
548
|
+
for (const [driver, held] of holders) holdersByDriver.get(driver)?.delete(held);
|
|
549
|
+
operation++;
|
|
550
|
+
restoring = null;
|
|
551
|
+
pending = null;
|
|
552
|
+
release();
|
|
553
|
+
unwatchConnectors();
|
|
554
|
+
connectorListeners.clear();
|
|
555
|
+
listeners.clear();
|
|
556
|
+
},
|
|
557
|
+
};
|
|
558
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { ChainClient } from "../clients/types";
|
|
2
|
+
|
|
3
|
+
/** Where a connection is: none, being opened by the user, being restored silently, or open. */
|
|
4
|
+
export type ConnectionStatus = "disconnected" | "connecting" | "reconnecting" | "connected";
|
|
5
|
+
|
|
6
|
+
/** One wallet a driver can connect, as the connect list shows it. */
|
|
7
|
+
export interface WalletConnector {
|
|
8
|
+
readonly id: string;
|
|
9
|
+
readonly name: string;
|
|
10
|
+
readonly icon?: string;
|
|
11
|
+
/** The wallet is present here now: an injected extension, an installed app. */
|
|
12
|
+
readonly installed?: boolean;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** The account a driver connected. */
|
|
16
|
+
export interface DriverAccount {
|
|
17
|
+
/** Chain-native address. */
|
|
18
|
+
readonly address: string;
|
|
19
|
+
/** EVM numeric chain id, or a CAIP-2 style id (`solana:mainnet`). */
|
|
20
|
+
readonly chainId?: number | string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface DriverState {
|
|
24
|
+
readonly status: ConnectionStatus;
|
|
25
|
+
readonly connectorId: string | null;
|
|
26
|
+
readonly account: DriverAccount | null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface DriverConnectOptions {
|
|
30
|
+
/** Called with a pairing URI when the connector hands off to another app or device. */
|
|
31
|
+
onDisplayUri?: (uri: string) => void;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The engine behind one wallet family's connections: wagmi for EVM, the light
|
|
36
|
+
* driver for adapter-based families. The connection store drives it and holds
|
|
37
|
+
* the one active connection; a driver never decides which family is active.
|
|
38
|
+
*/
|
|
39
|
+
export interface ConnectionDriver {
|
|
40
|
+
/** The connectors this driver can drive, in list order. */
|
|
41
|
+
connectors(): readonly WalletConnector[];
|
|
42
|
+
/**
|
|
43
|
+
* Called when the connector list changes: an EIP-6963 or Wallet Standard
|
|
44
|
+
* wallet announcing itself late. Without it the list is read once per call.
|
|
45
|
+
*/
|
|
46
|
+
watchConnectors?(listener: () => void): () => void;
|
|
47
|
+
getState(): DriverState;
|
|
48
|
+
/** Called on every state change: account, chain, connector, or a disconnect from the wallet side. */
|
|
49
|
+
subscribe(listener: () => void): () => void;
|
|
50
|
+
/** Prompts the user. Rejects when they decline or the wallet fails. */
|
|
51
|
+
connect(connectorId: string, options?: DriverConnectOptions): Promise<DriverAccount>;
|
|
52
|
+
/**
|
|
53
|
+
* Closes every connection the driver holds, or with a connectorId only that
|
|
54
|
+
* connector's, doing nothing when it is not open.
|
|
55
|
+
*/
|
|
56
|
+
disconnect(connectorId?: string): Promise<void>;
|
|
57
|
+
/**
|
|
58
|
+
* Restores a connector the user authorised before, without prompting.
|
|
59
|
+
* Resolves null only when the wallet says it is no longer authorised, which
|
|
60
|
+
* makes the store forget it. A connector that is not available yet (an
|
|
61
|
+
* EIP-6963 wallet still to announce itself) rejects instead, and the store
|
|
62
|
+
* keeps it for the next restore.
|
|
63
|
+
*/
|
|
64
|
+
reconnect(connectorId: string): Promise<DriverAccount | null>;
|
|
65
|
+
/**
|
|
66
|
+
* The per-chain client for the current account, or null. The store asks
|
|
67
|
+
* again only when the connector, address or chain changes.
|
|
68
|
+
*/
|
|
69
|
+
client?(state: DriverState): ChainClient | null | Promise<ChainClient | null>;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** What `useConnection()` returns: the single active connection across every family. */
|
|
73
|
+
export interface ConnectionState {
|
|
74
|
+
readonly status: ConnectionStatus;
|
|
75
|
+
readonly family: string | null;
|
|
76
|
+
readonly connector: WalletConnector | null;
|
|
77
|
+
readonly address: string | null;
|
|
78
|
+
readonly chainId: number | string | null;
|
|
79
|
+
readonly client: ChainClient | null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Where the store remembers the last connection. localStorage, wagmi's storage
|
|
84
|
+
* and React Native AsyncStorage all fit.
|
|
85
|
+
*/
|
|
86
|
+
export interface ConnectionStorage {
|
|
87
|
+
getItem(key: string): string | null | undefined | Promise<string | null | undefined>;
|
|
88
|
+
setItem(key: string, value: string): void | Promise<void>;
|
|
89
|
+
removeItem(key: string): void | Promise<void>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** The persisted record: which family and connector to restore, nothing else. */
|
|
93
|
+
export interface SavedConnection {
|
|
94
|
+
readonly family: string;
|
|
95
|
+
readonly connectorId: string;
|
|
96
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,8 @@ export {
|
|
|
3
3
|
WalletProvider,
|
|
4
4
|
useWeb3Config,
|
|
5
5
|
defaultChains,
|
|
6
|
+
useWalletBridge,
|
|
7
|
+
type WalletBridgeContextValue,
|
|
6
8
|
type WalletProviderProps,
|
|
7
9
|
type Web3Config,
|
|
8
10
|
} from "./providers";
|
|
@@ -75,3 +77,7 @@ export * from "./clients";
|
|
|
75
77
|
// verify pulls @noble/curves + bs58 (ESM-only) which Hermes rejects in the RN
|
|
76
78
|
// bundle ("import statement requires module mode"). It's server/web-side only —
|
|
77
79
|
// import it directly from "@multiplatform.one/web3/siws" (or the source path).
|
|
80
|
+
|
|
81
|
+
// Core contracts (MPO-385): the family registry, connection driver and store,
|
|
82
|
+
// and the message registry. Chain-SDK free, so Hermes-safe on the native entry.
|
|
83
|
+
export * from "./core";
|