Skip to content

Commit

Permalink
[dapp-kit] default storage to memory storage when local storage isn't…
Browse files Browse the repository at this point in the history
… available in an SSR context (#15554)

## Description 

dapp-kit breaks when used in a framework like Next since we default to
using local storage for persisting connection data which doesn't exist
in an SSR context. While we're working on better support for these
frameworks, this PR fixes the immediate breakage issue by defaulting to
memory storage when local storage isn't available. I also added the
option to entirely disable data persistence by setting `storage: null`
in the `WalletProvider`.

Most of this was copy-pasta'd from @Jordan-Mysten's Next PR, I did hoist
the storage determination logic up to the `WalletProvider` since I think
it might be more clear to consumers what storage ends up being used. I
don't have a super strong opinion on where this lives
(`WalletProvider.tsx` or `walletStore.ts`), so I'm glad to change this
back if anyone has a preference.

## Test Plan 
- Existing persistence tests pass
- Tested manually
- CI

---
If your changes are not user-facing and not a breaking change, you can
skip the following section. Otherwise, please indicate what changed, and
then add to the Release Notes section as highlighted during the release
process.

### Type of Change (Check all that apply)

- [ ] protocol change
- [ ] user-visible impact
- [ ] breaking change for a client SDKs
- [ ] breaking change for FNs (FN binary must upgrade)
- [ ] breaking change for validators or node operators (must upgrade
binaries)
- [ ] breaking change for on-chain data layout
- [ ] necessitate either a data wipe or data migration

### Release notes
  • Loading branch information
williamrobertson13 authored Jan 5, 2024
1 parent 6b31612 commit 9ba167b
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 15 deletions.
5 changes: 5 additions & 0 deletions .changeset/smooth-carrots-jam.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@mysten/dapp-kit': patch
---

Default storage to memory storage when local storage isn't available during SSR
25 changes: 12 additions & 13 deletions sdk/dapp-kit/src/components/WalletProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,25 @@ import type { ReactNode } from 'react';
import { useRef } from 'react';
import type { StateStorage } from 'zustand/middleware';

import {
DEFAULT_REQUIRED_FEATURES,
DEFAULT_STORAGE,
DEFAULT_STORAGE_KEY,
SUI_WALLET_NAME,
} from '../constants/walletDefaults.js';
import { WalletContext } from '../contexts/walletContext.js';
import { useAutoConnectWallet } from '../hooks/wallet/useAutoConnectWallet.js';
import { useUnsafeBurnerWallet } from '../hooks/wallet/useUnsafeBurnerWallet.js';
import { useWalletPropertiesChanged } from '../hooks/wallet/useWalletPropertiesChanged.js';
import { useWalletsChanged } from '../hooks/wallet/useWalletsChanged.js';
import { lightTheme } from '../themes/lightTheme.js';
import type { Theme } from '../themes/themeContract.js';
import { createInMemoryStore } from '../utils/stateStorage.js';
import { getRegisteredWallets } from '../utils/walletUtils.js';
import { createWalletStore } from '../walletStore.js';
import { InjectedThemeStyles } from './styling/InjectedThemeStyles.js';

type WalletProviderProps = {
export type WalletProviderProps = {
/** A list of wallets that are sorted to the top of the wallet list, if they are available to connect to. By default, wallets are sorted by the order they are loaded in. */
preferredWallets?: string[];

Expand All @@ -30,8 +37,8 @@ type WalletProviderProps = {
/** Enables automatically reconnecting to the most recently used wallet account upon mounting. */
autoConnect?: boolean;

/** Configures how the most recently connected to wallet account is stored. Defaults to using localStorage. */
storage?: StateStorage;
/** Configures how the most recently connected to wallet account is stored. Set to `null` to disable persisting state entirely. Defaults to using localStorage if it is available. */
storage?: StateStorage | null;

/** The key to use to store the most recently connected wallet account. */
storageKey?: string;
Expand All @@ -42,20 +49,12 @@ type WalletProviderProps = {
children: ReactNode;
};

const SUI_WALLET_NAME = 'Sui Wallet';

const DEFAULT_STORAGE_KEY = 'sui-dapp-kit:wallet-connection-info';

const DEFAULT_REQUIRED_FEATURES: (keyof WalletWithRequiredFeatures['features'])[] = [
'sui:signTransactionBlock',
];

export type { WalletWithFeatures };

export function WalletProvider({
preferredWallets = [SUI_WALLET_NAME],
requiredFeatures = DEFAULT_REQUIRED_FEATURES,
storage = localStorage,
storage = DEFAULT_STORAGE,
storageKey = DEFAULT_STORAGE_KEY,
enableUnsafeBurner = false,
autoConnect = false,
Expand All @@ -66,8 +65,8 @@ export function WalletProvider({
createWalletStore({
autoConnectEnabled: autoConnect,
wallets: getRegisteredWallets(preferredWallets, requiredFeatures),
storage: storage || createInMemoryStore(),
storageKey,
storage,
}),
);

Expand Down
17 changes: 17 additions & 0 deletions sdk/dapp-kit/src/constants/walletDefaults.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import type { WalletWithRequiredFeatures } from '@mysten/wallet-standard';

import { createInMemoryStore } from '../utils/stateStorage.js';

export const SUI_WALLET_NAME = 'Sui Wallet';

export const DEFAULT_STORAGE =
typeof window !== 'undefined' && window.localStorage ? localStorage : createInMemoryStore();

export const DEFAULT_STORAGE_KEY = 'sui-dapp-kit:wallet-connection-info';

export const DEFAULT_REQUIRED_FEATURES: (keyof WalletWithRequiredFeatures['features'])[] = [
'sui:signTransactionBlock',
];
19 changes: 19 additions & 0 deletions sdk/dapp-kit/src/utils/stateStorage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

import type { StateStorage } from 'zustand/middleware';

export function createInMemoryStore(): StateStorage {
const store = new Map();
return {
getItem(key: string) {
return store.get(key);
},
setItem(key: string, value: string) {
store.set(key, value);
},
removeItem(key: string) {
store.delete(key);
},
};
}
4 changes: 2 additions & 2 deletions sdk/docs/pages/dapp-kit/wallet-provider.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ All props are optional.
testing.
- `autoConnect` - Enables automatically reconnecting to the most recently used wallet account upon
mounting
- `storage` - Configures how the most recently connected to wallet account is stored. Defaults to
using localStorage.
- `storage` - Configures how the most recently connected to wallet account is stored. Set to `null`
to disable persisting state entirely. Defaults to using localStorage if it is available.
- `storageKey` - The key to use to store the most recently connected wallet account.
- `theme` - The theme to use for styling UI components. Defaults to using the light theme.

0 comments on commit 9ba167b

Please sign in to comment.