@w3ux/react-connect-kit 3.2.3 → 3.2.4

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.
@@ -1,3 +1,2 @@
1
- import type { HandleImportExtension } from './types';
2
- export declare const defaultHandleImportExtension: HandleImportExtension;
3
- export declare const DEFAULT_SS58 = 0;
1
+ import type { ProcessExtensionAccountsResult } from '@w3ux/types';
2
+ export declare const defaultProcessExtensionResult: ProcessExtensionAccountsResult;
@@ -1,11 +1,10 @@
1
- export const defaultHandleImportExtension = {
1
+ export const defaultProcessExtensionResult = {
2
2
  newAccounts: [],
3
3
  meta: {
4
4
  accountsToRemove: [],
5
5
  removedActiveAccount: null,
6
6
  },
7
7
  };
8
- export const DEFAULT_SS58 = 0;
9
8
 
10
9
  //# sourceMappingURL=defaults.js.map
11
10
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ExtensionAccountsProvider/defaults.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,4BAA4B,GAA0B;IACjE,WAAW,EAAE,EAAE;IACf,IAAI,EAAE;QACJ,gBAAgB,EAAE,EAAE;QACpB,oBAAoB,EAAE,IAAI;KAC3B;CACF,CAAA;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAA","file":"defaults.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { HandleImportExtension } from './types'\n\nexport const defaultHandleImportExtension: HandleImportExtension = {\n newAccounts: [],\n meta: {\n accountsToRemove: [],\n removedActiveAccount: null,\n },\n}\n\nexport const DEFAULT_SS58 = 0\n"]}
1
+ {"version":3,"sources":["../src/ExtensionAccountsProvider/defaults.ts"],"names":[],"mappings":"AAKA,MAAM,CAAC,MAAM,6BAA6B,GAAmC;IAC3E,WAAW,EAAE,EAAE;IACf,IAAI,EAAE;QACJ,gBAAgB,EAAE,EAAE;QACpB,oBAAoB,EAAE,IAAI;KAC3B;CACF,CAAA","file":"defaults.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { ProcessExtensionAccountsResult } from '@w3ux/types'\n\nexport const defaultProcessExtensionResult: ProcessExtensionAccountsResult = {\n newAccounts: [],\n meta: {\n accountsToRemove: [],\n removedActiveAccount: null,\n },\n}\n"]}
@@ -1,21 +1,19 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { createSafeContext, useEffectIgnoreInitial } from '@w3ux/hooks';
3
- import { connectedExtensions, enableExtensions, extensionsWithError, formatEnabledExtensions, getAccountsFromExtensions, getExtensionsById, } from '@w3ux/observables-connect/accounts';
4
- import { addExtensionToLocal, removeExtensionFromLocal, } from '@w3ux/observables-connect/extensions/local';
3
+ import { getAccountsFromExtensions, processExtensionAccounts, } from '@w3ux/observables-connect/accounts';
4
+ import { connectExtensions } from '@w3ux/observables-connect/extensions';
5
+ import { initialisedExtensions$ } from '@w3ux/observables-connect/extensions/observables';
5
6
  import { formatAccountSs58, localStorageOrDefault, setStateWithRef, } from '@w3ux/utils';
6
7
  import { useEffect, useRef, useState } from 'react';
7
8
  import { useExtensions } from '../ExtensionsProvider';
8
- import { useImportExtension } from './useImportExtension';
9
9
  import { connectActiveExtensionAccount, getActiveAccountLocal, getActiveExtensionAccount, } from './utils';
10
10
  export const [ExtensionAccountsContext, useExtensionAccounts] = createSafeContext();
11
11
  export const ExtensionAccountsProvider = ({ children, network, ss58, dappName, activeAccount, setActiveAccount, onExtensionEnabled, }) => {
12
- const { handleImportExtension } = useImportExtension();
13
- const { extensionsStatus, setExtensionStatus, removeExtensionStatus, checkingInjectedWeb3, extensionHasFeature, } = useExtensions();
12
+ const { extensionsStatus, gettingExtensions, extensionHasFeature, extensionCanConnect, } = useExtensions();
14
13
  const [extensionAccounts, setExtensionAccounts] = useState([]);
15
14
  const extensionAccountsRef = useRef(extensionAccounts);
16
15
  const [extensionAccountsSynced, setExtensionAccountsSynced] = useState('unsynced');
17
16
  const [extensionsInitialised, setExtensionsInitialised] = useState([]);
18
- const extensionsInitialisedRef = useRef(extensionsInitialised);
19
17
  const unsubs = useRef({});
20
18
  const maybeSetActiveAccount = (address) => {
21
19
  if (typeof setActiveAccount === 'function') {
@@ -31,33 +29,26 @@ export const ExtensionAccountsProvider = ({ children, network, ss58, dappName, a
31
29
  maybeSetActiveAccount(account?.address ?? null);
32
30
  };
33
31
  const connectActiveExtensions = async () => {
34
- const extensionIds = Object.keys(extensionsStatus);
35
- if (!extensionIds.length) {
32
+ const { connected } = await connectExtensions(dappName);
33
+ if (connected.size === 0) {
36
34
  return;
37
35
  }
38
- const rawExtensions = getExtensionsById(extensionIds);
39
- const enableResults = formatEnabledExtensions(rawExtensions, await enableExtensions(rawExtensions, dappName));
40
- const connected = connectedExtensions(enableResults);
41
- const withError = extensionsWithError(enableResults);
42
- Array.from(connected.keys()).forEach((id) => addExtensionToLocal(id));
43
- const initialAccounts = await getAccountsFromExtensions(connected);
36
+ const initialAccounts = await getAccountsFromExtensions(connected, ss58);
44
37
  const activeAccountInInitial = initialAccounts
45
38
  .map((acc) => ({
46
39
  ...acc,
47
40
  address: formatAccountSs58(acc.address, ss58),
48
41
  }))
49
42
  .find(({ address }) => address === getActiveAccountLocal(network, ss58));
50
- Array.from(withError.entries()).forEach(([id, state]) => {
51
- handleExtensionError(id, state.error);
52
- });
53
- Array.from(connected.keys()).forEach((id) => {
54
- setExtensionStatus(id, 'connected');
55
- updateInitialisedExtensions(id);
56
- });
57
43
  updateExtensionAccounts({ add: initialAccounts, remove: [] });
58
44
  const handleAccounts = (extensionId, accounts, signer) => {
59
- const { newAccounts, meta: { accountsToRemove }, } = handleImportExtension(extensionId, extensionAccountsRef.current, signer, accounts, network, ss58);
45
+ const { newAccounts, meta: { accountsToRemove }, } = processExtensionAccounts({
46
+ source: extensionId,
47
+ network,
48
+ ss58,
49
+ }, extensionAccountsRef.current, signer, accounts);
60
50
  updateExtensionAccounts({ add: newAccounts, remove: accountsToRemove });
51
+ return newAccounts;
61
52
  };
62
53
  for (const [id, { extension }] of Array.from(connected.entries())) {
63
54
  if (extensionHasFeature(id, 'subscribeAccounts')) {
@@ -72,69 +63,45 @@ export const ExtensionAccountsProvider = ({ children, network, ss58, dappName, a
72
63
  }
73
64
  };
74
65
  const connectExtensionAccounts = async (id) => {
75
- const extensionIds = Object.keys(extensionsStatus);
76
- const exists = extensionIds.find((key) => key === id) || undefined;
77
- if (!exists) {
78
- updateInitialisedExtensions(`unknown_extension_${extensionsInitialisedRef.current.length + 1}`);
79
- }
80
- else {
81
- try {
82
- const { enable } = window.injectedWeb3[id];
83
- const extension = await enable(dappName);
84
- if (extension !== undefined) {
85
- const handleAccounts = (accounts) => {
86
- const { newAccounts, meta: { removedActiveAccount, accountsToRemove }, } = handleImportExtension(id, extensionAccountsRef.current, extension.signer, accounts, network, ss58);
87
- if (!activeAccount) {
88
- const activeExtensionAccount = getActiveExtensionAccount(network, ss58, newAccounts);
89
- if (activeExtensionAccount?.address !== removedActiveAccount &&
90
- removedActiveAccount !== null) {
91
- connectActiveExtensionAccount(activeExtensionAccount, connectToAccount);
92
- }
93
- }
94
- updateExtensionAccounts({
95
- add: newAccounts,
96
- remove: accountsToRemove,
97
- });
98
- updateInitialisedExtensions(id);
99
- };
100
- addExtensionToLocal(id);
101
- maybeOnExtensionEnabled(id);
102
- setExtensionStatus(id, 'connected');
103
- if (!extensionHasFeature(id, 'subscribeAccounts')) {
104
- const accounts = await extension.accounts.get();
105
- handleAccounts(accounts);
106
- }
107
- else {
108
- const unsub = extension.accounts.subscribe((accounts) => {
109
- handleAccounts(accounts || []);
110
- });
111
- addToUnsubscribe(id, unsub);
66
+ if (extensionCanConnect(id)) {
67
+ const { connected } = await connectExtensions(dappName, [id]);
68
+ if (connected.size === 0) {
69
+ return;
70
+ }
71
+ const { extension } = connected.get(id);
72
+ const handleAccounts = (extensionId, accounts, signer) => {
73
+ const { newAccounts, meta: { removedActiveAccount, accountsToRemove }, } = processExtensionAccounts({
74
+ source: extensionId,
75
+ network,
76
+ ss58,
77
+ }, extensionAccountsRef.current, signer, accounts);
78
+ if (!activeAccount) {
79
+ const activeExtensionAccount = getActiveExtensionAccount(network, ss58, newAccounts);
80
+ if (activeExtensionAccount?.address !== removedActiveAccount &&
81
+ removedActiveAccount !== null) {
82
+ connectActiveExtensionAccount(activeExtensionAccount, connectToAccount);
112
83
  }
113
- return true;
114
84
  }
115
- }
116
- catch (err) {
117
- handleExtensionError(id, String(err));
118
- }
119
- }
120
- return false;
121
- };
122
- const handleExtensionError = (id, err) => {
123
- if (err.startsWith('Error')) {
124
- removeExtensionFromLocal(id);
125
- if (err.substring(0, 17) === 'NotInstalledError') {
126
- removeExtensionStatus(id);
85
+ updateExtensionAccounts({
86
+ add: newAccounts,
87
+ remove: accountsToRemove,
88
+ });
89
+ return newAccounts;
90
+ };
91
+ maybeOnExtensionEnabled(id);
92
+ if (!extensionHasFeature(id, 'subscribeAccounts')) {
93
+ const accounts = await extension.accounts.get();
94
+ handleAccounts(id, accounts, extension.signer);
127
95
  }
128
96
  else {
129
- setExtensionStatus(id, 'not_authenticated');
97
+ const unsub = extension.accounts.subscribe((accounts) => {
98
+ handleAccounts(id, accounts || [], extension.signer);
99
+ });
100
+ addToUnsubscribe(id, unsub);
130
101
  }
102
+ return true;
131
103
  }
132
- updateInitialisedExtensions(id);
133
- };
134
- const updateInitialisedExtensions = (id) => {
135
- if (!extensionsInitialisedRef.current.includes(id)) {
136
- setStateWithRef([...extensionsInitialisedRef.current].concat(id), setExtensionsInitialised, extensionsInitialisedRef);
137
- }
104
+ return false;
138
105
  };
139
106
  const updateExtensionAccounts = ({ add, remove, }) => {
140
107
  const newAccounts = [...extensionAccountsRef.current]
@@ -171,10 +138,9 @@ export const ExtensionAccountsProvider = ({ children, network, ss58, dappName, a
171
138
  });
172
139
  };
173
140
  const handleSyncExtensionAccounts = async () => {
174
- if (!checkingInjectedWeb3 && extensionAccountsSynced === 'unsynced') {
141
+ if (!gettingExtensions && extensionAccountsSynced === 'unsynced') {
175
142
  unsubscribe();
176
143
  setStateWithRef([], setExtensionAccounts, extensionAccountsRef);
177
- setStateWithRef([], setExtensionsInitialised, extensionsInitialisedRef);
178
144
  if (Object.keys(extensionsStatus).length) {
179
145
  const localExtensions = localStorageOrDefault(`active_extensions`, [], true);
180
146
  if (Object.keys(extensionsStatus).length && localExtensions.length) {
@@ -200,13 +166,21 @@ export const ExtensionAccountsProvider = ({ children, network, ss58, dappName, a
200
166
  useEffect(() => {
201
167
  handleSyncExtensionAccounts();
202
168
  return () => unsubscribe();
203
- }, [extensionsStatus, checkingInjectedWeb3, extensionAccountsSynced]);
169
+ }, [extensionsStatus, gettingExtensions, extensionAccountsSynced]);
204
170
  useEffectIgnoreInitial(() => {
205
- if (!checkingInjectedWeb3 &&
171
+ if (!gettingExtensions &&
206
172
  extensionsInitialised.length === Object.keys(extensionsStatus).length) {
207
173
  setExtensionAccountsSynced('synced');
208
174
  }
209
- }, [checkingInjectedWeb3, extensionsInitialised]);
175
+ }, [gettingExtensions, extensionsInitialised]);
176
+ useEffect(() => {
177
+ const sub = initialisedExtensions$.subscribe((initialised) => {
178
+ setExtensionsInitialised(initialised);
179
+ });
180
+ return () => {
181
+ sub.unsubscribe();
182
+ };
183
+ }, []);
210
184
  return (_jsx(ExtensionAccountsContext.Provider, { value: {
211
185
  connectExtensionAccounts,
212
186
  extensionAccountsSynced,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ExtensionAccountsProvider/index.tsx"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { createSafeContext, useEffectIgnoreInitial } from '@w3ux/hooks'\nimport {\n connectedExtensions,\n enableExtensions,\n extensionsWithError,\n formatEnabledExtensions,\n getAccountsFromExtensions,\n getExtensionsById,\n} from '@w3ux/observables-connect/accounts'\nimport {\n addExtensionToLocal,\n removeExtensionFromLocal,\n} from '@w3ux/observables-connect/extensions/local'\nimport type {\n ExtensionAccount,\n ExtensionInterface,\n ImportedAccount,\n Sync,\n VoidFn,\n} from '@w3ux/types'\nimport {\n formatAccountSs58,\n localStorageOrDefault,\n setStateWithRef,\n} from '@w3ux/utils'\nimport { useEffect, useRef, useState } from 'react'\nimport { useExtensions } from '../ExtensionsProvider'\nimport type {\n ExtensionAccountsContextInterface,\n ExtensionAccountsProviderProps,\n} from './types'\nimport { useImportExtension } from './useImportExtension'\nimport {\n connectActiveExtensionAccount,\n getActiveAccountLocal,\n getActiveExtensionAccount,\n} from './utils'\n\nexport const [ExtensionAccountsContext, useExtensionAccounts] =\n createSafeContext<ExtensionAccountsContextInterface>()\n\nexport const ExtensionAccountsProvider = ({\n children,\n network,\n ss58,\n dappName,\n activeAccount,\n setActiveAccount,\n onExtensionEnabled,\n}: ExtensionAccountsProviderProps) => {\n const { handleImportExtension } = useImportExtension()\n\n const {\n extensionsStatus,\n setExtensionStatus,\n removeExtensionStatus,\n checkingInjectedWeb3,\n extensionHasFeature,\n } = useExtensions()\n\n // Store connected extension accounts\n const [extensionAccounts, setExtensionAccounts] = useState<ImportedAccount[]>(\n []\n )\n const extensionAccountsRef = useRef(extensionAccounts)\n\n // Store whether extension accounts have been synced\n const [extensionAccountsSynced, setExtensionAccountsSynced] =\n useState<Sync>('unsynced')\n\n // Store extensions whose account subscriptions have been initialised\n const [extensionsInitialised, setExtensionsInitialised] = useState<string[]>(\n []\n )\n const extensionsInitialisedRef = useRef(extensionsInitialised)\n\n // Store unsubscribe handlers for connected extensions\n const unsubs = useRef<Record<string, VoidFn>>({})\n\n // Helper for setting active account. Ignores if not a valid function\n const maybeSetActiveAccount = (address: string) => {\n if (typeof setActiveAccount === 'function') {\n setActiveAccount(address ?? null)\n }\n }\n\n // Helper for calling extension enabled callback. Ignores if not a valid function\n const maybeOnExtensionEnabled = (id: string) => {\n if (typeof onExtensionEnabled === 'function') {\n onExtensionEnabled(id)\n }\n }\n\n const connectToAccount = (account: ImportedAccount | null) => {\n maybeSetActiveAccount(account?.address ?? null)\n }\n\n // connectActiveExtensions\n //\n // Connects to extensions that already have been connected to and stored in localStorage. Loop\n // through extensions and connect to accounts. If `activeAccount` exists locally, we wait until\n // all extensions are looped before connecting to it; there is no guarantee it still exists - must\n // explicitly find it\n const connectActiveExtensions = async () => {\n const extensionIds = Object.keys(extensionsStatus)\n if (!extensionIds.length) {\n return\n }\n\n // Iterate previously connected extensions and retreive valid `enable` functions\n // ------------------------------------------------------------------------------\n const rawExtensions = getExtensionsById(extensionIds)\n\n // Attempt to connect to extensions via `enable` and format the results\n const enableResults = formatEnabledExtensions(\n rawExtensions,\n await enableExtensions(rawExtensions, dappName)\n )\n\n // Retrieve the resulting connected extensions only\n const connected = connectedExtensions(enableResults)\n\n // Retrieve extensions that failed to connect\n const withError = extensionsWithError(enableResults)\n\n // Add connected extensions to local storage.\n Array.from(connected.keys()).forEach((id) => addExtensionToLocal(id))\n\n // Initial fetch of extension accounts to populate accounts & extensions state\n // ----------------------------------------------------------------------------\n\n // Get full list of imported accounts.\n const initialAccounts = await getAccountsFromExtensions(connected)\n\n // Get the active account if found in initial accounts. Format initial account addresses to the\n // correct ss58 format before finding\n const activeAccountInInitial = initialAccounts\n .map((acc) => ({\n ...acc,\n address: formatAccountSs58(acc.address, ss58),\n }))\n .find(({ address }) => address === getActiveAccountLocal(network, ss58))\n\n // Perform all initial state updates\n // ----------------------------------\n\n Array.from(withError.entries()).forEach(([id, state]) => {\n handleExtensionError(id, state.error)\n })\n\n Array.from(connected.keys()).forEach((id) => {\n setExtensionStatus(id, 'connected')\n updateInitialisedExtensions(id)\n })\n\n updateExtensionAccounts({ add: initialAccounts, remove: [] })\n\n // Initiate account subscriptions for connected extensions\n // --------------------------------------------------------\n\n // Handler function for each extension accounts subscription\n const handleAccounts = (\n extensionId: string,\n accounts: ExtensionAccount[],\n signer: unknown\n ) => {\n const {\n newAccounts,\n meta: { accountsToRemove },\n } = handleImportExtension(\n extensionId,\n extensionAccountsRef.current,\n signer,\n accounts,\n network,\n ss58\n )\n\n // Update added and removed accounts\n updateExtensionAccounts({ add: newAccounts, remove: accountsToRemove })\n }\n\n // Try to subscribe to accounts for each connected extension\n for (const [id, { extension }] of Array.from(connected.entries())) {\n // If enabled, subscribe to accounts.\n if (extensionHasFeature(id, 'subscribeAccounts')) {\n const unsub = extension.accounts.subscribe((accounts) => {\n handleAccounts(id, accounts || [], extension.signer)\n })\n // Add unsub to context ref\n addToUnsubscribe(id, unsub)\n }\n }\n\n // Connect to active account if found in initial accounts\n if (activeAccountInInitial) {\n connectActiveExtensionAccount(activeAccountInInitial, connectToAccount)\n }\n }\n\n // connectExtensionAccounts\n //\n // Similar to the above but only connects to a single extension. This is invoked by the user by\n // clicking on an extension. If activeAccount is not found here, it is simply ignored\n const connectExtensionAccounts = async (id: string): Promise<boolean> => {\n const extensionIds = Object.keys(extensionsStatus)\n const exists = extensionIds.find((key) => key === id) || undefined\n\n if (!exists) {\n updateInitialisedExtensions(\n `unknown_extension_${extensionsInitialisedRef.current.length + 1}`\n )\n } else {\n try {\n // Attempt to get extension `enable` property\n const { enable } = window.injectedWeb3[id]\n\n // Summons extension popup.\n const extension: ExtensionInterface = await enable(dappName)\n\n // Continue if `enable` succeeded, and if the current network is supported\n if (extension !== undefined) {\n // Handler for new accounts\n const handleAccounts = (accounts: ExtensionAccount[]) => {\n const {\n newAccounts,\n meta: { removedActiveAccount, accountsToRemove },\n } = handleImportExtension(\n id,\n extensionAccountsRef.current,\n extension.signer,\n accounts,\n network,\n ss58\n )\n // Set active account for network if not yet set\n if (!activeAccount) {\n const activeExtensionAccount = getActiveExtensionAccount(\n network,\n ss58,\n newAccounts\n )\n if (\n activeExtensionAccount?.address !== removedActiveAccount &&\n removedActiveAccount !== null\n ) {\n connectActiveExtensionAccount(\n activeExtensionAccount,\n connectToAccount\n )\n }\n }\n\n // Update extension accounts state\n updateExtensionAccounts({\n add: newAccounts,\n remove: accountsToRemove,\n })\n\n // Update initialised extensions\n updateInitialisedExtensions(id)\n }\n\n // Call optional `onExtensionEnabled` callback\n addExtensionToLocal(id)\n\n maybeOnExtensionEnabled(id)\n setExtensionStatus(id, 'connected')\n\n // If account subscriptions are not supported, simply get the account(s) from the extension. Otherwise, subscribe to accounts\n if (!extensionHasFeature(id, 'subscribeAccounts')) {\n const accounts = await extension.accounts.get()\n handleAccounts(accounts)\n } else {\n const unsub = extension.accounts.subscribe((accounts) => {\n handleAccounts(accounts || [])\n })\n addToUnsubscribe(id, unsub)\n }\n return true\n }\n } catch (err) {\n handleExtensionError(id, String(err))\n }\n }\n return false\n }\n\n // Handle errors when communiating with extensions\n const handleExtensionError = (id: string, err: string) => {\n // if not general error (maybe enabled but no accounts trust app)\n if (err.startsWith('Error')) {\n // remove extension from local `active_extensions`\n removeExtensionFromLocal(id)\n\n // extension not found (does not exist).\n if (err.substring(0, 17) === 'NotInstalledError') {\n removeExtensionStatus(id)\n } else {\n // declare extension as no imported accounts authenticated\n setExtensionStatus(id, 'not_authenticated')\n }\n }\n // mark extension as initialised\n updateInitialisedExtensions(id)\n }\n\n // Update initialised extensions\n const updateInitialisedExtensions = (id: string) => {\n if (!extensionsInitialisedRef.current.includes(id)) {\n setStateWithRef(\n [...extensionsInitialisedRef.current].concat(id),\n setExtensionsInitialised,\n extensionsInitialisedRef\n )\n }\n }\n\n // Add an extension account to context state\n const updateExtensionAccounts = ({\n add,\n remove,\n }: {\n add: ExtensionAccount[]\n remove: ExtensionAccount[]\n }) => {\n // Add new accounts and remove any removed accounts\n const newAccounts = [...extensionAccountsRef.current]\n .concat(add)\n .filter((a) => remove.find((s) => s.address === a.address) === undefined)\n\n if (remove.length) {\n // Unsubscribe from removed accounts\n unsubAccounts(remove)\n\n // Remove active account if it is being forgotten\n if (\n activeAccount &&\n remove.find(({ address }) => address === activeAccount) !== undefined\n ) {\n maybeSetActiveAccount(null)\n }\n }\n\n setStateWithRef(newAccounts, setExtensionAccounts, extensionAccountsRef)\n }\n\n // Add an extension id to unsubscribe state\n const addToUnsubscribe = (id: string, unsub: VoidFn) => {\n unsubs.current[id] = unsub\n }\n\n // Handle unsubscribing of an removed extension accounts\n const unsubAccounts = (accounts: ImportedAccount[]) => {\n // Unsubscribe and remove unsub from context ref\n if (accounts.length) {\n for (const { address } of accounts) {\n if (extensionAccountsRef.current.find((a) => a.address === address)) {\n const unsub = unsubs.current[address]\n if (unsub) {\n unsub()\n delete unsubs.current[address]\n }\n }\n }\n }\n }\n\n // Unsubscrbe all account subscriptions\n const unsubscribe = () => {\n Object.values(unsubs.current).forEach((unsub) => {\n unsub()\n })\n }\n\n const handleSyncExtensionAccounts = async () => {\n // Wait for injectedWeb3 check to finish before starting account import process\n if (!checkingInjectedWeb3 && extensionAccountsSynced === 'unsynced') {\n // Unsubscribe from all accounts and reset state\n unsubscribe()\n setStateWithRef([], setExtensionAccounts, extensionAccountsRef)\n setStateWithRef([], setExtensionsInitialised, extensionsInitialisedRef)\n // If extensions have been fetched, get accounts if extensions exist and local extensions\n // exist (previously connected)\n if (Object.keys(extensionsStatus).length) {\n // get active extensions\n const localExtensions = localStorageOrDefault(\n `active_extensions`,\n [],\n true\n )\n if (Object.keys(extensionsStatus).length && localExtensions.length) {\n setExtensionAccountsSynced('syncing')\n await connectActiveExtensions()\n }\n }\n\n // Syncing is complete. Also covers case where no extensions were found\n setExtensionAccountsSynced('synced')\n }\n }\n\n // Get extension accounts based on the provided ss58 prefix\n const getExtensionAccounts = (ss58Prefix: number): ImportedAccount[] =>\n extensionAccounts\n .map((account) => {\n const formattedAddress = formatAccountSs58(account.address, ss58Prefix)\n if (!formattedAddress) {\n return null\n }\n return {\n ...account,\n address: formattedAddress,\n }\n })\n // Remove null entries resulting from invalid formatted addresses\n .filter((account) => account !== null)\n\n // Re-sync extensions accounts on `unsynced`\n useEffect(() => {\n handleSyncExtensionAccounts()\n\n return () => unsubscribe()\n }, [extensionsStatus, checkingInjectedWeb3, extensionAccountsSynced])\n\n // Once initialised extensions equal total extensions present in `injectedWeb3`, mark extensions\n // as fetched\n useEffectIgnoreInitial(() => {\n if (\n !checkingInjectedWeb3 &&\n extensionsInitialised.length === Object.keys(extensionsStatus).length\n ) {\n setExtensionAccountsSynced('synced')\n }\n }, [checkingInjectedWeb3, extensionsInitialised])\n\n return (\n <ExtensionAccountsContext.Provider\n value={{\n connectExtensionAccounts,\n extensionAccountsSynced,\n getExtensionAccounts,\n }}\n >\n {children}\n </ExtensionAccountsContext.Provider>\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/ExtensionAccountsProvider/index.tsx"],"names":[],"mappings":";AAGA,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AACvE,OAAO,EACL,yBAAyB,EACzB,wBAAwB,GACzB,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,sCAAsC,CAAA;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kDAAkD,CAAA;AAOzF,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,GAChB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AAKrD,OAAO,EACL,6BAA6B,EAC7B,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,SAAS,CAAA;AAEhB,MAAM,CAAC,MAAM,CAAC,wBAAwB,EAAE,oBAAoB,CAAC,GAC3D,iBAAiB,EAAqC,CAAA;AAExD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,EACxC,QAAQ,EACR,OAAO,EACP,IAAI,EACJ,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,kBAAkB,GACa,EAAE,EAAE;IACnC,MAAM,EACJ,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,mBAAmB,GACpB,GAAG,aAAa,EAAE,CAAA;IAGnB,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,GAAG,QAAQ,CACxD,EAAE,CACH,CAAA;IACD,MAAM,oBAAoB,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAA;IAItD,MAAM,CAAC,uBAAuB,EAAE,0BAA0B,CAAC,GACzD,QAAQ,CAAO,UAAU,CAAC,CAAA;IAG5B,MAAM,CAAC,qBAAqB,EAAE,wBAAwB,CAAC,GAAG,QAAQ,CAChE,EAAE,CACH,CAAA;IAGD,MAAM,MAAM,GAAG,MAAM,CAAyB,EAAE,CAAC,CAAA;IAGjD,MAAM,qBAAqB,GAAG,CAAC,OAAe,EAAE,EAAE;QAChD,IAAI,OAAO,gBAAgB,KAAK,UAAU,EAAE,CAAC;YAC3C,gBAAgB,CAAC,OAAO,IAAI,IAAI,CAAC,CAAA;QACnC,CAAC;IACH,CAAC,CAAA;IAGD,MAAM,uBAAuB,GAAG,CAAC,EAAU,EAAE,EAAE;QAC7C,IAAI,OAAO,kBAAkB,KAAK,UAAU,EAAE,CAAC;YAC7C,kBAAkB,CAAC,EAAE,CAAC,CAAA;QACxB,CAAC;IACH,CAAC,CAAA;IAED,MAAM,gBAAgB,GAAG,CAAC,OAA+B,EAAE,EAAE;QAC3D,qBAAqB,CAAC,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC,CAAA;IACjD,CAAC,CAAA;IAMD,MAAM,uBAAuB,GAAG,KAAK,IAAI,EAAE;QACzC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAA;QACvD,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACzB,OAAM;QACR,CAAC;QAGD,MAAM,eAAe,GAAG,MAAM,yBAAyB,CAAC,SAAS,EAAE,IAAI,CAAC,CAAA;QAIxE,MAAM,sBAAsB,GAAG,eAAe;aAC3C,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;YACb,GAAG,GAAG;YACN,OAAO,EAAE,iBAAiB,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC;SAC9C,CAAC,CAAC;aACF,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,KAAK,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAA;QAG1E,uBAAuB,CAAC,EAAE,GAAG,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAA;QAM7D,MAAM,cAAc,GAAG,CACrB,WAAmB,EACnB,QAA4B,EAC5B,MAAe,EACf,EAAE;YACF,MAAM,EACJ,WAAW,EACX,IAAI,EAAE,EAAE,gBAAgB,EAAE,GAC3B,GAAG,wBAAwB,CAC1B;gBACE,MAAM,EAAE,WAAW;gBACnB,OAAO;gBACP,IAAI;aACL,EACD,oBAAoB,CAAC,OAAO,EAC5B,MAAM,EACN,QAAQ,CACT,CAAA;YAGD,uBAAuB,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAA;YACvE,OAAO,WAAW,CAAA;QACpB,CAAC,CAAA;QAGD,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;YAElE,IAAI,mBAAmB,CAAC,EAAE,EAAE,mBAAmB,CAAC,EAAE,CAAC;gBACjD,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACtD,cAAc,CAAC,EAAE,EAAE,QAAQ,IAAI,EAAE,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;gBACtD,CAAC,CAAC,CAAA;gBAEF,gBAAgB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;YAC7B,CAAC;QACH,CAAC;QAGD,IAAI,sBAAsB,EAAE,CAAC;YAC3B,6BAA6B,CAAC,sBAAsB,EAAE,gBAAgB,CAAC,CAAA;QACzE,CAAC;IACH,CAAC,CAAA;IAGD,MAAM,wBAAwB,GAAG,KAAK,EAAE,EAAU,EAAoB,EAAE;QACtE,IAAI,mBAAmB,CAAC,EAAE,CAAC,EAAE,CAAC;YAC5B,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,iBAAiB,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;YAC7D,IAAI,SAAS,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;gBACzB,OAAM;YACR,CAAC;YACD,MAAM,EAAE,SAAS,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YAGvC,MAAM,cAAc,GAAG,CACrB,WAAmB,EACnB,QAA4B,EAC5B,MAAe,EACf,EAAE;gBACF,MAAM,EACJ,WAAW,EACX,IAAI,EAAE,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,GACjD,GAAG,wBAAwB,CAC1B;oBACE,MAAM,EAAE,WAAW;oBACnB,OAAO;oBACP,IAAI;iBACL,EACD,oBAAoB,CAAC,OAAO,EAC5B,MAAM,EACN,QAAQ,CACT,CAAA;gBAED,IAAI,CAAC,aAAa,EAAE,CAAC;oBACnB,MAAM,sBAAsB,GAAG,yBAAyB,CACtD,OAAO,EACP,IAAI,EACJ,WAAW,CACZ,CAAA;oBACD,IACE,sBAAsB,EAAE,OAAO,KAAK,oBAAoB;wBACxD,oBAAoB,KAAK,IAAI,EAC7B,CAAC;wBACD,6BAA6B,CAC3B,sBAAsB,EACtB,gBAAgB,CACjB,CAAA;oBACH,CAAC;gBACH,CAAC;gBAID,uBAAuB,CAAC;oBACtB,GAAG,EAAE,WAAW;oBAChB,MAAM,EAAE,gBAAgB;iBACzB,CAAC,CAAA;gBACF,OAAO,WAAW,CAAA;YACpB,CAAC,CAAA;YAGD,uBAAuB,CAAC,EAAE,CAAC,CAAA;YAG3B,IAAI,CAAC,mBAAmB,CAAC,EAAE,EAAE,mBAAmB,CAAC,EAAE,CAAC;gBAClD,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAA;gBAC/C,cAAc,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;YAChD,CAAC;iBAAM,CAAC;gBACN,MAAM,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,QAAQ,EAAE,EAAE;oBACtD,cAAc,CAAC,EAAE,EAAE,QAAQ,IAAI,EAAE,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;gBACtD,CAAC,CAAC,CAAA;gBACF,gBAAgB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAA;YAC7B,CAAC;YACD,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC,CAAA;IAGD,MAAM,uBAAuB,GAAG,CAAC,EAC/B,GAAG,EACH,MAAM,GAIP,EAAE,EAAE;QAEH,MAAM,WAAW,GAAG,CAAC,GAAG,oBAAoB,CAAC,OAAO,CAAC;aAClD,MAAM,CAAC,GAAG,CAAC;aACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,SAAS,CAAC,CAAA;QAE3E,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAElB,aAAa,CAAC,MAAM,CAAC,CAAA;YAGrB,IACE,aAAa;gBACb,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,KAAK,aAAa,CAAC,KAAK,SAAS,EACrE,CAAC;gBACD,qBAAqB,CAAC,IAAI,CAAC,CAAA;YAC7B,CAAC;QACH,CAAC;QAED,eAAe,CAAC,WAAW,EAAE,oBAAoB,EAAE,oBAAoB,CAAC,CAAA;IAC1E,CAAC,CAAA;IAGD,MAAM,gBAAgB,GAAG,CAAC,EAAU,EAAE,KAAa,EAAE,EAAE;QACrD,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,KAAK,CAAA;IAC5B,CAAC,CAAA;IAGD,MAAM,aAAa,GAAG,CAAC,QAA2B,EAAE,EAAE;QAEpD,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;YACpB,KAAK,MAAM,EAAE,OAAO,EAAE,IAAI,QAAQ,EAAE,CAAC;gBACnC,IAAI,oBAAoB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,EAAE,CAAC;oBACpE,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;oBACrC,IAAI,KAAK,EAAE,CAAC;wBACV,KAAK,EAAE,CAAA;wBACP,OAAO,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;oBAChC,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAA;IAGD,MAAM,WAAW,GAAG,GAAG,EAAE;QACvB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YAC9C,KAAK,EAAE,CAAA;QACT,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,MAAM,2BAA2B,GAAG,KAAK,IAAI,EAAE;QAE7C,IAAI,CAAC,iBAAiB,IAAI,uBAAuB,KAAK,UAAU,EAAE,CAAC;YAEjE,WAAW,EAAE,CAAA;YACb,eAAe,CAAC,EAAE,EAAE,oBAAoB,EAAE,oBAAoB,CAAC,CAAA;YAG/D,IAAI,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,MAAM,EAAE,CAAC;gBAEzC,MAAM,eAAe,GAAG,qBAAqB,CAC3C,mBAAmB,EACnB,EAAE,EACF,IAAI,CACL,CAAA;gBACD,IAAI,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,MAAM,IAAI,eAAe,CAAC,MAAM,EAAE,CAAC;oBACnE,0BAA0B,CAAC,SAAS,CAAC,CAAA;oBACrC,MAAM,uBAAuB,EAAE,CAAA;gBACjC,CAAC;YACH,CAAC;YAGD,0BAA0B,CAAC,QAAQ,CAAC,CAAA;QACtC,CAAC;IACH,CAAC,CAAA;IAGD,MAAM,oBAAoB,GAAG,CAAC,UAAkB,EAAqB,EAAE,CACrE,iBAAiB;SACd,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QACf,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QACvE,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,OAAO,IAAI,CAAA;QACb,CAAC;QACD,OAAO;YACL,GAAG,OAAO;YACV,OAAO,EAAE,gBAAgB;SAC1B,CAAA;IACH,CAAC,CAAC;SAED,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,CAAC,CAAA;IAG1C,SAAS,CAAC,GAAG,EAAE;QACb,2BAA2B,EAAE,CAAA;QAE7B,OAAO,GAAG,EAAE,CAAC,WAAW,EAAE,CAAA;IAC5B,CAAC,EAAE,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,uBAAuB,CAAC,CAAC,CAAA;IAIlE,sBAAsB,CAAC,GAAG,EAAE;QAC1B,IACE,CAAC,iBAAiB;YAClB,qBAAqB,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,MAAM,EACrE,CAAC;YACD,0BAA0B,CAAC,QAAQ,CAAC,CAAA;QACtC,CAAC;IACH,CAAC,EAAE,CAAC,iBAAiB,EAAE,qBAAqB,CAAC,CAAC,CAAA;IAG9C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,GAAG,GAAG,sBAAsB,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,EAAE;YAC3D,wBAAwB,CAAC,WAAW,CAAC,CAAA;QACvC,CAAC,CAAC,CAAA;QACF,OAAO,GAAG,EAAE;YACV,GAAG,CAAC,WAAW,EAAE,CAAA;QACnB,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CACL,KAAC,wBAAwB,CAAC,QAAQ,IAChC,KAAK,EAAE;YACL,wBAAwB;YACxB,uBAAuB;YACvB,oBAAoB;SACrB,YAEA,QAAQ,GACyB,CACrC,CAAA;AACH,CAAC,CAAA","file":"index.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport { createSafeContext, useEffectIgnoreInitial } from '@w3ux/hooks'\nimport {\n getAccountsFromExtensions,\n processExtensionAccounts,\n} from '@w3ux/observables-connect/accounts'\nimport { connectExtensions } from '@w3ux/observables-connect/extensions'\nimport { initialisedExtensions$ } from '@w3ux/observables-connect/extensions/observables'\nimport type {\n ExtensionAccount,\n ImportedAccount,\n Sync,\n VoidFn,\n} from '@w3ux/types'\nimport {\n formatAccountSs58,\n localStorageOrDefault,\n setStateWithRef,\n} from '@w3ux/utils'\nimport { useEffect, useRef, useState } from 'react'\nimport { useExtensions } from '../ExtensionsProvider'\nimport type {\n ExtensionAccountsContextInterface,\n ExtensionAccountsProviderProps,\n} from './types'\nimport {\n connectActiveExtensionAccount,\n getActiveAccountLocal,\n getActiveExtensionAccount,\n} from './utils'\n\nexport const [ExtensionAccountsContext, useExtensionAccounts] =\n createSafeContext<ExtensionAccountsContextInterface>()\n\nexport const ExtensionAccountsProvider = ({\n children,\n network,\n ss58,\n dappName,\n activeAccount,\n setActiveAccount,\n onExtensionEnabled,\n}: ExtensionAccountsProviderProps) => {\n const {\n extensionsStatus,\n gettingExtensions,\n extensionHasFeature,\n extensionCanConnect,\n } = useExtensions()\n\n // Store connected extension accounts\n const [extensionAccounts, setExtensionAccounts] = useState<ImportedAccount[]>(\n []\n )\n const extensionAccountsRef = useRef(extensionAccounts)\n\n // Store whether extension accounts have been synced\n // TODO: Use observable to update this state\n const [extensionAccountsSynced, setExtensionAccountsSynced] =\n useState<Sync>('unsynced')\n\n // Stores initialised extensions\n const [extensionsInitialised, setExtensionsInitialised] = useState<string[]>(\n []\n )\n\n // Store unsubscribe handlers for connected extensions\n const unsubs = useRef<Record<string, VoidFn>>({})\n\n // Helper for setting active account. Ignores if not a valid function\n const maybeSetActiveAccount = (address: string) => {\n if (typeof setActiveAccount === 'function') {\n setActiveAccount(address ?? null)\n }\n }\n\n // Helper for calling extension enabled callback. Ignores if not a valid function\n const maybeOnExtensionEnabled = (id: string) => {\n if (typeof onExtensionEnabled === 'function') {\n onExtensionEnabled(id)\n }\n }\n\n const connectToAccount = (account: ImportedAccount | null) => {\n maybeSetActiveAccount(account?.address ?? null)\n }\n\n // Connects to extensions that already have been connected to and stored in localStorage. Loop\n // through extensions and connect to accounts. If `activeAccount` exists locally, we wait until\n // all extensions are looped before connecting to it; there is no guarantee it still exists - must\n // explicitly find it\n const connectActiveExtensions = async () => {\n const { connected } = await connectExtensions(dappName)\n if (connected.size === 0) {\n return\n }\n\n // Get full list of imported accounts\n const initialAccounts = await getAccountsFromExtensions(connected, ss58)\n\n // Get the active account if found in initial accounts. Format initial account addresses to the\n // correct ss58 format before finding\n const activeAccountInInitial = initialAccounts\n .map((acc) => ({\n ...acc,\n address: formatAccountSs58(acc.address, ss58),\n }))\n .find(({ address }) => address === getActiveAccountLocal(network, ss58))\n\n // Perform initial account state update\n updateExtensionAccounts({ add: initialAccounts, remove: [] })\n\n // Initiate account subscriptions for connected extensions\n // --------------------------------------------------------\n\n // Handler function for each extension accounts subscription\n const handleAccounts = (\n extensionId: string,\n accounts: ExtensionAccount[],\n signer: unknown\n ) => {\n const {\n newAccounts,\n meta: { accountsToRemove },\n } = processExtensionAccounts(\n {\n source: extensionId,\n network,\n ss58,\n },\n extensionAccountsRef.current,\n signer,\n accounts\n )\n\n // Update added and removed accounts\n updateExtensionAccounts({ add: newAccounts, remove: accountsToRemove })\n return newAccounts\n }\n\n // Try to subscribe to accounts for each connected extension\n for (const [id, { extension }] of Array.from(connected.entries())) {\n // If enabled, subscribe to accounts.\n if (extensionHasFeature(id, 'subscribeAccounts')) {\n const unsub = extension.accounts.subscribe((accounts) => {\n handleAccounts(id, accounts || [], extension.signer)\n })\n // Add unsub to context ref\n addToUnsubscribe(id, unsub)\n }\n }\n\n // Connect to active account if found in initial accounts\n if (activeAccountInInitial) {\n connectActiveExtensionAccount(activeAccountInInitial, connectToAccount)\n }\n }\n\n // Connects to a single extension. If activeAccount is not found here, it is simply ignored\n const connectExtensionAccounts = async (id: string): Promise<boolean> => {\n if (extensionCanConnect(id)) {\n const { connected } = await connectExtensions(dappName, [id])\n if (connected.size === 0) {\n return\n }\n const { extension } = connected.get(id)\n\n // Handler for new accounts\n const handleAccounts = (\n extensionId: string,\n accounts: ExtensionAccount[],\n signer: unknown\n ) => {\n const {\n newAccounts,\n meta: { removedActiveAccount, accountsToRemove },\n } = processExtensionAccounts(\n {\n source: extensionId,\n network,\n ss58,\n },\n extensionAccountsRef.current,\n signer,\n accounts\n )\n // Set active account for network if not yet set\n if (!activeAccount) {\n const activeExtensionAccount = getActiveExtensionAccount(\n network,\n ss58,\n newAccounts\n )\n if (\n activeExtensionAccount?.address !== removedActiveAccount &&\n removedActiveAccount !== null\n ) {\n connectActiveExtensionAccount(\n activeExtensionAccount,\n connectToAccount\n )\n }\n }\n\n // Update extension accounts state\n // TODO: Use account observables instead\n updateExtensionAccounts({\n add: newAccounts,\n remove: accountsToRemove,\n })\n return newAccounts\n }\n\n // Call optional `onExtensionEnabled` callback\n maybeOnExtensionEnabled(id)\n\n // If account subscriptions are not supported, simply get the account(s) from the extension. Otherwise, subscribe to accounts\n if (!extensionHasFeature(id, 'subscribeAccounts')) {\n const accounts = await extension.accounts.get()\n handleAccounts(id, accounts, extension.signer)\n } else {\n const unsub = extension.accounts.subscribe((accounts) => {\n handleAccounts(id, accounts || [], extension.signer)\n })\n addToUnsubscribe(id, unsub)\n }\n return true\n }\n return false\n }\n\n // Add an extension account to context state\n const updateExtensionAccounts = ({\n add,\n remove,\n }: {\n add: ExtensionAccount[]\n remove: ExtensionAccount[]\n }) => {\n // Add new accounts and remove any removed accounts\n const newAccounts = [...extensionAccountsRef.current]\n .concat(add)\n .filter((a) => remove.find((s) => s.address === a.address) === undefined)\n\n if (remove.length) {\n // Unsubscribe from removed accounts\n unsubAccounts(remove)\n\n // Remove active account if it is being forgotten\n if (\n activeAccount &&\n remove.find(({ address }) => address === activeAccount) !== undefined\n ) {\n maybeSetActiveAccount(null)\n }\n }\n\n setStateWithRef(newAccounts, setExtensionAccounts, extensionAccountsRef)\n }\n\n // Add an extension id to unsubscribe state\n const addToUnsubscribe = (id: string, unsub: VoidFn) => {\n unsubs.current[id] = unsub\n }\n\n // Handle unsubscribing of an removed extension accounts\n const unsubAccounts = (accounts: ImportedAccount[]) => {\n // Unsubscribe and remove unsub from context ref\n if (accounts.length) {\n for (const { address } of accounts) {\n if (extensionAccountsRef.current.find((a) => a.address === address)) {\n const unsub = unsubs.current[address]\n if (unsub) {\n unsub()\n delete unsubs.current[address]\n }\n }\n }\n }\n }\n\n // Unsubscribe all account subscriptions\n const unsubscribe = () => {\n Object.values(unsubs.current).forEach((unsub) => {\n unsub()\n })\n }\n\n const handleSyncExtensionAccounts = async () => {\n // Wait for injectedWeb3 check to finish before starting account import process\n if (!gettingExtensions && extensionAccountsSynced === 'unsynced') {\n // Unsubscribe from all accounts and reset state\n unsubscribe()\n setStateWithRef([], setExtensionAccounts, extensionAccountsRef)\n // If extensions have been fetched, get accounts if extensions exist and local extensions\n // exist (previously connected)\n if (Object.keys(extensionsStatus).length) {\n // get active extensions\n const localExtensions = localStorageOrDefault(\n `active_extensions`,\n [],\n true\n )\n if (Object.keys(extensionsStatus).length && localExtensions.length) {\n setExtensionAccountsSynced('syncing')\n await connectActiveExtensions()\n }\n }\n\n // Syncing is complete. Also covers case where no extensions were found\n setExtensionAccountsSynced('synced')\n }\n }\n\n // Get extension accounts based on the provided ss58 prefix\n const getExtensionAccounts = (ss58Prefix: number): ImportedAccount[] =>\n extensionAccounts\n .map((account) => {\n const formattedAddress = formatAccountSs58(account.address, ss58Prefix)\n if (!formattedAddress) {\n return null\n }\n return {\n ...account,\n address: formattedAddress,\n }\n })\n // Remove null entries resulting from invalid formatted addresses\n .filter((account) => account !== null)\n\n // Re-sync extensions accounts on `unsynced`\n useEffect(() => {\n handleSyncExtensionAccounts()\n\n return () => unsubscribe()\n }, [extensionsStatus, gettingExtensions, extensionAccountsSynced])\n\n // Once initialised extensions equal total extensions present in `injectedWeb3`, mark extensions\n // as fetched\n useEffectIgnoreInitial(() => {\n if (\n !gettingExtensions &&\n extensionsInitialised.length === Object.keys(extensionsStatus).length\n ) {\n setExtensionAccountsSynced('synced')\n }\n }, [gettingExtensions, extensionsInitialised])\n\n // Subscribes to observables and updates state\n useEffect(() => {\n const sub = initialisedExtensions$.subscribe((initialised) => {\n setExtensionsInitialised(initialised)\n })\n return () => {\n sub.unsubscribe()\n }\n }, [])\n\n return (\n <ExtensionAccountsContext.Provider\n value={{\n connectExtensionAccounts,\n extensionAccountsSynced,\n getExtensionAccounts,\n }}\n >\n {children}\n </ExtensionAccountsContext.Provider>\n )\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { ExtensionAccount, ImportedAccount, MaybeString, Sync } from '@w3ux/types';
1
+ import type { ImportedAccount, MaybeString, Sync } from '@w3ux/types';
2
2
  import type { ReactNode } from 'react';
3
3
  export interface ExtensionAccountsContextInterface {
4
4
  connectExtensionAccounts: (id?: string) => Promise<boolean>;
@@ -14,10 +14,3 @@ export interface ExtensionAccountsProviderProps {
14
14
  setActiveAccount?: (address: MaybeString) => void;
15
15
  onExtensionEnabled?: (id: string) => void;
16
16
  }
17
- export interface HandleImportExtension {
18
- newAccounts: ExtensionAccount[];
19
- meta: {
20
- accountsToRemove: ExtensionAccount[];
21
- removedActiveAccount: MaybeString;
22
- };
23
- }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ExtensionAccountsProvider/types.ts"],"names":[],"mappings":"","file":"types.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type {\n ExtensionAccount,\n ImportedAccount,\n MaybeString,\n Sync,\n} from '@w3ux/types'\nimport type { ReactNode } from 'react'\n\nexport interface ExtensionAccountsContextInterface {\n connectExtensionAccounts: (id?: string) => Promise<boolean>\n extensionAccountsSynced: Sync\n getExtensionAccounts: (ss58: number) => ImportedAccount[]\n}\n\nexport interface ExtensionAccountsProviderProps {\n children: ReactNode\n network: string\n ss58: number\n dappName: string\n activeAccount?: MaybeString\n setActiveAccount?: (address: MaybeString) => void\n onExtensionEnabled?: (id: string) => void\n}\n\nexport interface HandleImportExtension {\n newAccounts: ExtensionAccount[]\n meta: {\n accountsToRemove: ExtensionAccount[]\n removedActiveAccount: MaybeString\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/ExtensionAccountsProvider/types.ts"],"names":[],"mappings":"","file":"types.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { ImportedAccount, MaybeString, Sync } from '@w3ux/types'\nimport type { ReactNode } from 'react'\n\nexport interface ExtensionAccountsContextInterface {\n connectExtensionAccounts: (id?: string) => Promise<boolean>\n extensionAccountsSynced: Sync\n getExtensionAccounts: (ss58: number) => ImportedAccount[]\n}\n\nexport interface ExtensionAccountsProviderProps {\n children: ReactNode\n network: string\n ss58: number\n dappName: string\n activeAccount?: MaybeString\n setActiveAccount?: (address: MaybeString) => void\n onExtensionEnabled?: (id: string) => void\n}\n"]}
@@ -1,6 +1,4 @@
1
- import type { ExtensionAccount, ExternalAccount, ImportedAccount } from '@w3ux/types';
1
+ import type { ExtensionAccount, ImportedAccount } from '@w3ux/types';
2
2
  export declare const getActiveAccountLocal: (network: string, ss58: number) => string | null;
3
3
  export declare const getActiveExtensionAccount: (network: string, ss58: number, accounts: ExtensionAccount[]) => ExtensionAccount;
4
4
  export declare const connectActiveExtensionAccount: (account: ExtensionAccount | null, callback: (account: ImportedAccount | null) => void) => void;
5
- export declare const getInExternalAccounts: (accounts: ExtensionAccount[], network: string) => ExternalAccount[];
6
- export declare const getLocalExternalAccounts: (network?: string) => ExternalAccount[];
@@ -15,17 +15,6 @@ export const connectActiveExtensionAccount = (account, callback) => {
15
15
  callback(account);
16
16
  }
17
17
  };
18
- export const getInExternalAccounts = (accounts, network) => {
19
- const localExternalAccounts = getLocalExternalAccounts(network);
20
- return (localExternalAccounts.filter((a) => (accounts || []).find((b) => b.address === a.address) !== undefined) || []);
21
- };
22
- export const getLocalExternalAccounts = (network) => {
23
- let localAccounts = localStorageOrDefault('external_accounts', [], true);
24
- if (network) {
25
- localAccounts = localAccounts.filter((l) => l.network === network);
26
- }
27
- return localAccounts;
28
- };
29
18
 
30
19
  //# sourceMappingURL=utils.js.map
31
20
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ExtensionAccountsProvider/utils.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAOtE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,OAAe,EACf,IAAY,EACG,EAAE;IACjB,MAAM,OAAO,GAAG,qBAAqB,CAAC,GAAG,OAAO,iBAAiB,EAAE,IAAI,CAAC,CAAA;IAExE,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QACzD,IAAI,gBAAgB,EAAE,CAAC;YACrB,OAAO,gBAAgB,CAAA;QACzB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAGD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,OAAe,EACf,IAAY,EACZ,QAA4B,EAC5B,EAAE,CACF,QAAQ,CAAC,IAAI,CACX,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,KAAK,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,CAClE,IAAI,IAAI,CAAA;AAGX,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,OAAgC,EAChC,QAAmD,EACnD,EAAE;IACF,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,QAAQ,CAAC,OAAO,CAAC,CAAA;IACnB,CAAC;AACH,CAAC,CAAA;AAOD,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,QAA4B,EAC5B,OAAe,EACf,EAAE;IACF,MAAM,qBAAqB,GAAG,wBAAwB,CAAC,OAAO,CAAC,CAAA;IAE/D,OAAO,CACL,qBAAqB,CAAC,MAAM,CAC1B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,SAAS,CAC3E,IAAI,EAAE,CACR,CAAA;AACH,CAAC,CAAA;AAGD,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,OAAgB,EAAE,EAAE;IAC3D,IAAI,aAAa,GAAG,qBAAqB,CACvC,mBAAmB,EACnB,EAAE,EACF,IAAI,CACgB,CAAA;IACtB,IAAI,OAAO,EAAE,CAAC;QACZ,aAAa,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,CAAC,CAAA;IACpE,CAAC;IACD,OAAO,aAAa,CAAA;AACtB,CAAC,CAAA","file":"utils.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type {\n ExtensionAccount,\n ExternalAccount,\n ImportedAccount,\n} from '@w3ux/types'\nimport { formatAccountSs58, localStorageOrDefault } from '@w3ux/utils'\n\n/*------------------------------------------------------------\n Active account utils.\n ------------------------------------------------------------*/\n\n// Gets local `active_acount` for a network.\nexport const getActiveAccountLocal = (\n network: string,\n ss58: number\n): string | null => {\n const account = localStorageOrDefault(`${network}_active_account`, null)\n\n if (account !== null) {\n const formattedAddress = formatAccountSs58(account, ss58)\n if (formattedAddress) {\n return formattedAddress\n }\n }\n return null\n}\n\n// Checks if the local active account is the provided accounts.\nexport const getActiveExtensionAccount = (\n network: string,\n ss58: number,\n accounts: ExtensionAccount[]\n) =>\n accounts.find(\n ({ address }) => address === getActiveAccountLocal(network, ss58)\n ) ?? null\n\n// Connects to active account, and calls an optional callback, if provided.\nexport const connectActiveExtensionAccount = (\n account: ExtensionAccount | null,\n callback: (account: ImportedAccount | null) => void\n) => {\n if (account !== null) {\n callback(account)\n }\n}\n\n/*------------------------------------------------------------\n External account utils.\n ------------------------------------------------------------*/\n\n// Gets accounts that exist in local `external_accounts`.\nexport const getInExternalAccounts = (\n accounts: ExtensionAccount[],\n network: string\n) => {\n const localExternalAccounts = getLocalExternalAccounts(network)\n\n return (\n localExternalAccounts.filter(\n (a) => (accounts || []).find((b) => b.address === a.address) !== undefined\n ) || []\n )\n}\n\n// Gets local external accounts for a network.\nexport const getLocalExternalAccounts = (network?: string) => {\n let localAccounts = localStorageOrDefault<ExternalAccount[]>(\n 'external_accounts',\n [],\n true\n ) as ExternalAccount[]\n if (network) {\n localAccounts = localAccounts.filter((l) => l.network === network)\n }\n return localAccounts\n}\n"]}
1
+ {"version":3,"sources":["../src/ExtensionAccountsProvider/utils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAGtE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACnC,OAAe,EACf,IAAY,EACG,EAAE;IACjB,MAAM,OAAO,GAAG,qBAAqB,CAAC,GAAG,OAAO,iBAAiB,EAAE,IAAI,CAAC,CAAA;IAExE,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;QACzD,IAAI,gBAAgB,EAAE,CAAC;YACrB,OAAO,gBAAgB,CAAA;QACzB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAGD,MAAM,CAAC,MAAM,yBAAyB,GAAG,CACvC,OAAe,EACf,IAAY,EACZ,QAA4B,EAC5B,EAAE,CACF,QAAQ,CAAC,IAAI,CACX,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,KAAK,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,CAClE,IAAI,IAAI,CAAA;AAGX,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAC3C,OAAgC,EAChC,QAAmD,EACnD,EAAE;IACF,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,QAAQ,CAAC,OAAO,CAAC,CAAA;IACnB,CAAC;AACH,CAAC,CAAA","file":"utils.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { ExtensionAccount, ImportedAccount } from '@w3ux/types'\nimport { formatAccountSs58, localStorageOrDefault } from '@w3ux/utils'\n\n// Gets local `active_acount` for a network.\nexport const getActiveAccountLocal = (\n network: string,\n ss58: number\n): string | null => {\n const account = localStorageOrDefault(`${network}_active_account`, null)\n\n if (account !== null) {\n const formattedAddress = formatAccountSs58(account, ss58)\n if (formattedAddress) {\n return formattedAddress\n }\n }\n return null\n}\n\n// Checks if the local active account is the provided accounts.\nexport const getActiveExtensionAccount = (\n network: string,\n ss58: number,\n accounts: ExtensionAccount[]\n) =>\n accounts.find(\n ({ address }) => address === getActiveAccountLocal(network, ss58)\n ) ?? null\n\n// Connects to active account, and calls an optional callback, if provided.\nexport const connectActiveExtensionAccount = (\n account: ExtensionAccount | null,\n callback: (account: ImportedAccount | null) => void\n) => {\n if (account !== null) {\n callback(account)\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import type { ReactNode } from 'react';
1
+ import { type ReactNode } from 'react';
2
2
  import type { ExtensionsContextInterface } from './types';
3
3
  export declare const ExtensionsContext: import("react").Context<ExtensionsContextInterface>, useExtensions: () => ExtensionsContextInterface;
4
4
  export declare const ExtensionsProvider: ({ children }: {
@@ -1,17 +1,14 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import extensions from '@w3ux/extension-assets';
3
3
  import { createSafeContext } from '@w3ux/hooks';
4
- import { extensionsStatus$, gettingExtensions$, } from '@w3ux/observables-connect';
5
4
  import { canConnect, getExtensions, getStatus, removeStatus, setStatus, } from '@w3ux/observables-connect/extensions';
6
- import { setStateWithRef } from '@w3ux/utils';
7
- import { useEffect, useRef, useState } from 'react';
5
+ import { extensionsStatus$, gettingExtensions$, } from '@w3ux/observables-connect/extensions/observables';
6
+ import { useEffect, useState } from 'react';
8
7
  import { combineLatest } from 'rxjs';
9
8
  export const [ExtensionsContext, useExtensions] = createSafeContext();
10
9
  export const ExtensionsProvider = ({ children }) => {
11
- const [checkingInjectedWeb3, setCheckingInjectedWeb3] = useState(true);
12
- const checkingInjectedWeb3Ref = useRef(checkingInjectedWeb3);
10
+ const [gettingExtensions, setGettingExtensions] = useState(true);
13
11
  const [extensionsStatus, setExtensionsStatus] = useState({});
14
- const extensionsStatusRef = useRef(extensionsStatus);
15
12
  const setExtensionStatus = (id, status) => {
16
13
  setStatus(id, status);
17
14
  };
@@ -29,17 +26,17 @@ export const ExtensionsProvider = ({ children }) => {
29
26
  const sub = combineLatest([
30
27
  gettingExtensions$,
31
28
  extensionsStatus$,
32
- ]).subscribe(([checking, exts]) => {
33
- setStateWithRef(checking, setCheckingInjectedWeb3, checkingInjectedWeb3Ref);
34
- setStateWithRef(exts, setExtensionsStatus, extensionsStatusRef);
29
+ ]).subscribe(([getting, status]) => {
30
+ setGettingExtensions(getting);
31
+ setExtensionsStatus(status);
35
32
  });
36
33
  return () => {
37
34
  sub.unsubscribe();
38
35
  };
39
36
  }, []);
40
37
  return (_jsx(ExtensionsContext.Provider, { value: {
41
- extensionsStatus: extensionsStatusRef.current,
42
- checkingInjectedWeb3,
38
+ extensionsStatus,
39
+ gettingExtensions,
43
40
  setExtensionStatus,
44
41
  removeExtensionStatus,
45
42
  extensionInstalled,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ExtensionsProvider/index.tsx"],"names":[],"mappings":";AAGA,OAAO,UAAU,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EACL,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,UAAU,EACV,aAAa,EACb,SAAS,EACT,YAAY,EACZ,SAAS,GACV,MAAM,sCAAsC,CAAA;AAE7C,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AAGpC,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,aAAa,CAAC,GAC7C,iBAAiB,EAA8B,CAAA;AAEjD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,EAAE,QAAQ,EAA2B,EAAE,EAAE;IAE1E,MAAM,CAAC,oBAAoB,EAAE,uBAAuB,CAAC,GACnD,QAAQ,CAAU,IAAI,CAAC,CAAA;IACzB,MAAM,uBAAuB,GAAG,MAAM,CAAC,oBAAoB,CAAC,CAAA;IAG5D,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAmB,EAAE,CAAC,CAAA;IAC9E,MAAM,mBAAmB,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAA;IAGpD,MAAM,kBAAkB,GAAG,CAAC,EAAU,EAAE,MAAuB,EAAE,EAAE;QACjE,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;IACvB,CAAC,CAAA;IAGD,MAAM,qBAAqB,GAAG,CAAC,EAAU,EAAE,EAAE;QAC3C,YAAY,CAAC,EAAE,CAAC,CAAA;IAClB,CAAC,CAAA;IAGD,MAAM,kBAAkB,GAAG,CAAC,EAAU,EAAW,EAAE,CACjD,SAAS,CAAC,EAAE,CAAC,KAAK,SAAS,CAAA;IAG7B,MAAM,mBAAmB,GAAG,CAAC,EAAU,EAAW,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;IAGnE,MAAM,mBAAmB,GAAG,CAAC,EAAU,EAAE,OAAe,EAAW,EAAE;QACnE,MAAM,QAAQ,GAAG,UAAU,CAAC,EAAE,CAAC,EAAE,QAAQ,IAAI,EAAE,CAAA;QAC/C,OAAO,QAAQ,KAAK,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IACvD,CAAC,CAAA;IAGD,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,EAAE,CAAA;QACf,MAAM,GAAG,GAAG,aAAa,CAAC;YACxB,kBAAkB;YAClB,iBAAiB;SAClB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE;YAChC,eAAe,CACb,QAAQ,EACR,uBAAuB,EACvB,uBAAuB,CACxB,CAAA;YACD,eAAe,CAAC,IAAI,EAAE,mBAAmB,EAAE,mBAAmB,CAAC,CAAA;QACjE,CAAC,CAAC,CAAA;QACF,OAAO,GAAG,EAAE;YACV,GAAG,CAAC,WAAW,EAAE,CAAA;QACnB,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CACL,KAAC,iBAAiB,CAAC,QAAQ,IACzB,KAAK,EAAE;YACL,gBAAgB,EAAE,mBAAmB,CAAC,OAAO;YAC7C,oBAAoB;YACpB,kBAAkB;YAClB,qBAAqB;YACrB,kBAAkB;YAClB,mBAAmB;YACnB,mBAAmB;SACpB,YAEA,QAAQ,GACkB,CAC9B,CAAA;AACH,CAAC,CAAA","file":"index.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport extensions from '@w3ux/extension-assets'\nimport { createSafeContext } from '@w3ux/hooks'\nimport {\n extensionsStatus$,\n gettingExtensions$,\n} from '@w3ux/observables-connect'\nimport {\n canConnect,\n getExtensions,\n getStatus,\n removeStatus,\n setStatus,\n} from '@w3ux/observables-connect/extensions'\nimport type { ExtensionsStatus, ExtensionStatus } from '@w3ux/types'\nimport { setStateWithRef } from '@w3ux/utils'\nimport type { ReactNode } from 'react'\nimport { useEffect, useRef, useState } from 'react'\nimport { combineLatest } from 'rxjs'\nimport type { ExtensionsContextInterface } from './types'\n\nexport const [ExtensionsContext, useExtensions] =\n createSafeContext<ExtensionsContextInterface>()\n\nexport const ExtensionsProvider = ({ children }: { children: ReactNode }) => {\n // Store whether extensions are being checked\n const [checkingInjectedWeb3, setCheckingInjectedWeb3] =\n useState<boolean>(true)\n const checkingInjectedWeb3Ref = useRef(checkingInjectedWeb3)\n\n // Store discovered extensions along with their status\n const [extensionsStatus, setExtensionsStatus] = useState<ExtensionsStatus>({})\n const extensionsStatusRef = useRef(extensionsStatus)\n\n // Setter for an extension status\n const setExtensionStatus = (id: string, status: ExtensionStatus) => {\n setStatus(id, status)\n }\n\n // Removes an extension from the `extensionsStatus` state\n const removeExtensionStatus = (id: string) => {\n removeStatus(id)\n }\n\n // Checks if an extension has been installed\n const extensionInstalled = (id: string): boolean =>\n getStatus(id) !== undefined\n\n // Checks whether an extension can be connected to\n const extensionCanConnect = (id: string): boolean => canConnect(id)\n\n // Checks whether an extension supports a feature.\n const extensionHasFeature = (id: string, feature: string): boolean => {\n const features = extensions[id]?.features || []\n return features === '*' || features.includes(feature)\n }\n\n // Fetches the extensions and sets the state\n useEffect(() => {\n getExtensions()\n const sub = combineLatest([\n gettingExtensions$,\n extensionsStatus$,\n ]).subscribe(([checking, exts]) => {\n setStateWithRef(\n checking,\n setCheckingInjectedWeb3,\n checkingInjectedWeb3Ref\n )\n setStateWithRef(exts, setExtensionsStatus, extensionsStatusRef)\n })\n return () => {\n sub.unsubscribe()\n }\n }, [])\n\n return (\n <ExtensionsContext.Provider\n value={{\n extensionsStatus: extensionsStatusRef.current,\n checkingInjectedWeb3,\n setExtensionStatus,\n removeExtensionStatus,\n extensionInstalled,\n extensionCanConnect,\n extensionHasFeature,\n }}\n >\n {children}\n </ExtensionsContext.Provider>\n )\n}\n"]}
1
+ {"version":3,"sources":["../src/ExtensionsProvider/index.tsx"],"names":[],"mappings":";AAGA,OAAO,UAAU,MAAM,wBAAwB,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,EACL,UAAU,EACV,aAAa,EACb,SAAS,EACT,YAAY,EACZ,SAAS,GACV,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EACL,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,kDAAkD,CAAA;AAEzD,OAAO,EAAkB,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AAGpC,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,aAAa,CAAC,GAC7C,iBAAiB,EAA8B,CAAA;AAEjD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,EAAE,QAAQ,EAA2B,EAAE,EAAE;IAE1E,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,GAAG,QAAQ,CAAU,IAAI,CAAC,CAAA;IAGzE,MAAM,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,GAAG,QAAQ,CAAmB,EAAE,CAAC,CAAA;IAG9E,MAAM,kBAAkB,GAAG,CAAC,EAAU,EAAE,MAAuB,EAAE,EAAE;QACjE,SAAS,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;IACvB,CAAC,CAAA;IAGD,MAAM,qBAAqB,GAAG,CAAC,EAAU,EAAE,EAAE;QAC3C,YAAY,CAAC,EAAE,CAAC,CAAA;IAClB,CAAC,CAAA;IAGD,MAAM,kBAAkB,GAAG,CAAC,EAAU,EAAW,EAAE,CACjD,SAAS,CAAC,EAAE,CAAC,KAAK,SAAS,CAAA;IAG7B,MAAM,mBAAmB,GAAG,CAAC,EAAU,EAAW,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAA;IAGnE,MAAM,mBAAmB,GAAG,CAAC,EAAU,EAAE,OAAe,EAAW,EAAE;QACnE,MAAM,QAAQ,GAAG,UAAU,CAAC,EAAE,CAAC,EAAE,QAAQ,IAAI,EAAE,CAAA;QAC/C,OAAO,QAAQ,KAAK,GAAG,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IACvD,CAAC,CAAA;IAGD,SAAS,CAAC,GAAG,EAAE;QACb,aAAa,EAAE,CAAA;QACf,MAAM,GAAG,GAAG,aAAa,CAAC;YACxB,kBAAkB;YAClB,iBAAiB;SAClB,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE;YACjC,oBAAoB,CAAC,OAAO,CAAC,CAAA;YAC7B,mBAAmB,CAAC,MAAM,CAAC,CAAA;QAC7B,CAAC,CAAC,CAAA;QACF,OAAO,GAAG,EAAE;YACV,GAAG,CAAC,WAAW,EAAE,CAAA;QACnB,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,OAAO,CACL,KAAC,iBAAiB,CAAC,QAAQ,IACzB,KAAK,EAAE;YACL,gBAAgB;YAChB,iBAAiB;YACjB,kBAAkB;YAClB,qBAAqB;YACrB,kBAAkB;YAClB,mBAAmB;YACnB,mBAAmB;SACpB,YAEA,QAAQ,GACkB,CAC9B,CAAA;AACH,CAAC,CAAA","file":"index.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport extensions from '@w3ux/extension-assets'\nimport { createSafeContext } from '@w3ux/hooks'\nimport {\n canConnect,\n getExtensions,\n getStatus,\n removeStatus,\n setStatus,\n} from '@w3ux/observables-connect/extensions'\nimport {\n extensionsStatus$,\n gettingExtensions$,\n} from '@w3ux/observables-connect/extensions/observables'\nimport type { ExtensionsStatus, ExtensionStatus } from '@w3ux/types'\nimport { type ReactNode, useEffect, useState } from 'react'\nimport { combineLatest } from 'rxjs'\nimport type { ExtensionsContextInterface } from './types'\n\nexport const [ExtensionsContext, useExtensions] =\n createSafeContext<ExtensionsContextInterface>()\n\nexport const ExtensionsProvider = ({ children }: { children: ReactNode }) => {\n // Store whether extensions are being fetched\n const [gettingExtensions, setGettingExtensions] = useState<boolean>(true)\n\n // Store discovered extensions along with their status\n const [extensionsStatus, setExtensionsStatus] = useState<ExtensionsStatus>({})\n\n // Setter for an extension status\n const setExtensionStatus = (id: string, status: ExtensionStatus) => {\n setStatus(id, status)\n }\n\n // Removes an extension status\n const removeExtensionStatus = (id: string) => {\n removeStatus(id)\n }\n\n // Checks if an extension has been installed\n const extensionInstalled = (id: string): boolean =>\n getStatus(id) !== undefined\n\n // Checks whether an extension can be connected to\n const extensionCanConnect = (id: string): boolean => canConnect(id)\n\n // Checks whether an extension supports a feature\n const extensionHasFeature = (id: string, feature: string): boolean => {\n const features = extensions[id]?.features || []\n return features === '*' || features.includes(feature)\n }\n\n // Subscribes to observables and updates state\n useEffect(() => {\n getExtensions()\n const sub = combineLatest([\n gettingExtensions$,\n extensionsStatus$,\n ]).subscribe(([getting, status]) => {\n setGettingExtensions(getting)\n setExtensionsStatus(status)\n })\n return () => {\n sub.unsubscribe()\n }\n }, [])\n\n return (\n <ExtensionsContext.Provider\n value={{\n extensionsStatus,\n gettingExtensions,\n setExtensionStatus,\n removeExtensionStatus,\n extensionInstalled,\n extensionCanConnect,\n extensionHasFeature,\n }}\n >\n {children}\n </ExtensionsContext.Provider>\n )\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import type { ExtensionStatus } from '@w3ux/types';
2
2
  export interface ExtensionsContextInterface {
3
- checkingInjectedWeb3: boolean;
3
+ gettingExtensions: boolean;
4
4
  extensionsStatus: Record<string, ExtensionStatus>;
5
5
  setExtensionStatus: (id: string, status: ExtensionStatus) => void;
6
6
  removeExtensionStatus: (id: string) => void;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/ExtensionsProvider/types.ts"],"names":[],"mappings":"","file":"types.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { ExtensionStatus } from '@w3ux/types'\n\n// Extensions context interface.\nexport interface ExtensionsContextInterface {\n checkingInjectedWeb3: boolean\n extensionsStatus: Record<string, ExtensionStatus>\n setExtensionStatus: (id: string, status: ExtensionStatus) => void\n removeExtensionStatus: (id: string) => void\n extensionInstalled: (id: string) => boolean\n extensionCanConnect: (id: string) => boolean\n extensionHasFeature: (id: string, feature: string) => boolean\n}\n"]}
1
+ {"version":3,"sources":["../src/ExtensionsProvider/types.ts"],"names":[],"mappings":"","file":"types.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { ExtensionStatus } from '@w3ux/types'\n\n// Extensions context interface.\nexport interface ExtensionsContextInterface {\n gettingExtensions: boolean\n extensionsStatus: Record<string, ExtensionStatus>\n setExtensionStatus: (id: string, status: ExtensionStatus) => void\n removeExtensionStatus: (id: string) => void\n extensionInstalled: (id: string) => boolean\n extensionCanConnect: (id: string) => boolean\n extensionHasFeature: (id: string, feature: string) => boolean\n}\n"]}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@w3ux/react-connect-kit",
3
- "version": "3.2.3",
3
+ "version": "3.2.4",
4
4
  "license": "GPL-3.0-only",
5
5
  "dependencies": {
6
6
  "@w3ux/extension-assets": "^2.2.0",
7
7
  "@w3ux/hooks": "^2.1.0",
8
- "@w3ux/observables-connect": "^0.9.3",
8
+ "@w3ux/observables-connect": "^0.9.12",
9
9
  "@w3ux/utils": "^2.0.8"
10
10
  },
11
11
  "type": "module",
@@ -1,5 +0,0 @@
1
- import type { ExtensionAccount } from '@w3ux/types';
2
- import type { HandleImportExtension } from './types';
3
- export declare const useImportExtension: () => {
4
- handleImportExtension: (id: string, currentAccounts: ExtensionAccount[], signer: unknown, newAccounts: ExtensionAccount[], network: string, ss58: number) => HandleImportExtension;
5
- };
@@ -1,47 +0,0 @@
1
- import { formatAccountSs58, isValidAddress } from '@w3ux/utils';
2
- import { defaultHandleImportExtension } from './defaults';
3
- import { getActiveAccountLocal, getInExternalAccounts } from './utils';
4
- export const useImportExtension = () => {
5
- const handleImportExtension = (id, currentAccounts, signer, newAccounts, network, ss58) => {
6
- if (!newAccounts.length) {
7
- return defaultHandleImportExtension;
8
- }
9
- newAccounts = newAccounts.filter(({ address }) => isValidAddress(address));
10
- newAccounts
11
- .map((account) => {
12
- const formattedAddress = formatAccountSs58(account.address, ss58);
13
- if (!formattedAddress) {
14
- return null;
15
- }
16
- account.address = formattedAddress;
17
- return account;
18
- })
19
- .filter((account) => account !== null);
20
- const inExternal = getInExternalAccounts(newAccounts, network);
21
- const removedAccounts = currentAccounts
22
- .filter((j) => j.source === id)
23
- .filter((j) => !newAccounts.find((i) => i.address === j.address));
24
- const removedActiveAccount = removedAccounts.find(({ address }) => address === getActiveAccountLocal(network, ss58))?.address || null;
25
- newAccounts = newAccounts.filter(({ address }) => !currentAccounts.find((j) => j.address === address && j.source !== 'external'));
26
- newAccounts = newAccounts.map(({ address, name }) => ({
27
- address,
28
- name,
29
- source: id,
30
- signer,
31
- }));
32
- return {
33
- newAccounts,
34
- meta: {
35
- accountsToRemove: [...inExternal, ...removedAccounts],
36
- removedActiveAccount,
37
- },
38
- };
39
- };
40
- return {
41
- handleImportExtension,
42
- };
43
- };
44
-
45
- //# sourceMappingURL=useImportExtension.js.map
46
-
47
- //# sourceMappingURL=useImportExtension.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ExtensionAccountsProvider/useImportExtension.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC/D,OAAO,EAAE,4BAA4B,EAAE,MAAM,YAAY,CAAA;AAEzD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAEtE,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,EAAE;IAIrC,MAAM,qBAAqB,GAAG,CAC5B,EAAU,EACV,eAAmC,EACnC,MAAe,EACf,WAA+B,EAC/B,OAAe,EACf,IAAY,EACW,EAAE;QACzB,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC;YACxB,OAAO,4BAA4B,CAAA;QACrC,CAAC;QAGD,WAAW,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAA;QAG1E,WAAW;aACR,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;YACf,MAAM,gBAAgB,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;YACjE,IAAI,CAAC,gBAAgB,EAAE,CAAC;gBACtB,OAAO,IAAI,CAAA;YACb,CAAC;YACD,OAAO,CAAC,OAAO,GAAG,gBAAgB,CAAA;YAClC,OAAO,OAAO,CAAA;QAChB,CAAC,CAAC;aAED,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,KAAK,IAAI,CAAC,CAAA;QAGxC,MAAM,UAAU,GAAG,qBAAqB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QAG9D,MAAM,eAAe,GAAG,eAAe;aACpC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,EAAE,CAAC;aAC9B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;QAGnE,MAAM,oBAAoB,GACxB,eAAe,CAAC,IAAI,CAClB,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,KAAK,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,CAClE,EAAE,OAAO,IAAI,IAAI,CAAA;QAGpB,WAAW,GAAG,WAAW,CAAC,MAAM,CAC9B,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CACd,CAAC,eAAe,CAAC,IAAI,CACnB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,MAAM,KAAK,UAAU,CACxD,CACJ,CAAA;QAGD,WAAW,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;YACpD,OAAO;YACP,IAAI;YACJ,MAAM,EAAE,EAAE;YACV,MAAM;SACP,CAAC,CAAC,CAAA;QAEH,OAAO;YACL,WAAW;YACX,IAAI,EAAE;gBACJ,gBAAgB,EAAE,CAAC,GAAG,UAAU,EAAE,GAAG,eAAe,CAAC;gBACrD,oBAAoB;aACrB;SACF,CAAA;IACH,CAAC,CAAA;IAED,OAAO;QACL,qBAAqB;KACtB,CAAA;AACH,CAAC,CAAA","file":"useImportExtension.js","sourcesContent":["/* @license Copyright 2024 w3ux authors & contributors\nSPDX-License-Identifier: GPL-3.0-only */\n\nimport type { ExtensionAccount } from '@w3ux/types'\nimport { formatAccountSs58, isValidAddress } from '@w3ux/utils'\nimport { defaultHandleImportExtension } from './defaults'\nimport type { HandleImportExtension } from './types'\nimport { getActiveAccountLocal, getInExternalAccounts } from './utils'\n\nexport const useImportExtension = () => {\n // Handles importing of extension accounts.\n //\n // Gets accounts to be imported and commits them to state.\n const handleImportExtension = (\n id: string,\n currentAccounts: ExtensionAccount[],\n signer: unknown,\n newAccounts: ExtensionAccount[],\n network: string,\n ss58: number\n ): HandleImportExtension => {\n if (!newAccounts.length) {\n return defaultHandleImportExtension\n }\n\n // Remove accounts that do not contain correctly formatted addresses.\n newAccounts = newAccounts.filter(({ address }) => isValidAddress(address))\n\n // Reformat addresses to ensure default ss58 format.\n newAccounts\n .map((account) => {\n const formattedAddress = formatAccountSs58(account.address, ss58)\n if (!formattedAddress) {\n return null\n }\n account.address = formattedAddress\n return account\n })\n // Remove null entries resulting from invalid formatted addresses.\n .filter((account) => account !== null)\n\n // Remove `newAccounts` from local external accounts if present.\n const inExternal = getInExternalAccounts(newAccounts, network)\n\n // Find any accounts that have been removed from this extension.\n const removedAccounts = currentAccounts\n .filter((j) => j.source === id)\n .filter((j) => !newAccounts.find((i) => i.address === j.address))\n\n // Check whether active account is present in forgotten accounts.\n const removedActiveAccount =\n removedAccounts.find(\n ({ address }) => address === getActiveAccountLocal(network, ss58)\n )?.address || null\n\n // Remove accounts that have already been added to `currentAccounts` via another extension.\n newAccounts = newAccounts.filter(\n ({ address }) =>\n !currentAccounts.find(\n (j) => j.address === address && j.source !== 'external'\n )\n )\n\n // Format accounts properties.\n newAccounts = newAccounts.map(({ address, name }) => ({\n address,\n name,\n source: id,\n signer,\n }))\n\n return {\n newAccounts,\n meta: {\n accountsToRemove: [...inExternal, ...removedAccounts],\n removedActiveAccount,\n },\n }\n }\n\n return {\n handleImportExtension,\n }\n}\n"]}