@@ -21,6 +21,11 @@ interface PendingRequest {
2121 reject : ( error : any ) => void
2222}
2323
24+ interface PersistedSession {
25+ connectedAddress : string
26+ chainId : number | null
27+ }
28+
2429const SIGNING_METHODS = new Set ( [
2530 "eth_sendTransaction" ,
2631 "eth_signTransaction" ,
@@ -38,19 +43,44 @@ export function createFlowDevWalletProvider(config: FlowDevWalletConfig = {}) {
3843 } = config
3944
4045 let popup : Window | null = null
41- let connectedAddress : string | null = null
42- let chainId : number | null = null
46+ const storageKey = getSessionStorageKey ( walletUrl )
47+ const initialSession = readPersistedSession ( storageKey )
48+ let connectedAddress : string | null = initialSession ?. connectedAddress ?? null
49+ let chainId : number | null = initialSession ?. chainId ?? null
4350 let popupReady = false
4451 let requestId = 0
4552 const pending = new Map < number , PendingRequest > ( )
4653 const listeners = new Map < EventName , Set < Handler > > ( )
54+ let connectWaiters : Array < { resolve : ( accounts : string [ ] ) => void ; reject : ( error : Error ) => void } > = [ ]
4755
4856 function emit ( event : EventName , ...args : any [ ] ) {
4957 listeners . get ( event ) ?. forEach ( ( fn ) => fn ( ...args ) )
5058 }
5159
5260 let readyResolvers : Array < ( ) => void > = [ ]
5361
62+ function persistSession ( ) {
63+ if ( typeof window === "undefined" ) return
64+ if ( ! connectedAddress ) {
65+ window . localStorage . removeItem ( storageKey )
66+ return
67+ }
68+ const session : PersistedSession = { connectedAddress, chainId }
69+ window . localStorage . setItem ( storageKey , JSON . stringify ( session ) )
70+ }
71+
72+ function resolveConnectWaiters ( accounts : string [ ] ) {
73+ const waiters = connectWaiters
74+ connectWaiters = [ ]
75+ waiters . forEach ( ( { resolve } ) => resolve ( accounts ) )
76+ }
77+
78+ function rejectConnectWaiters ( error : Error ) {
79+ const waiters = connectWaiters
80+ connectWaiters = [ ]
81+ waiters . forEach ( ( { reject } ) => reject ( error ) )
82+ }
83+
5484 function onMessage ( event : MessageEvent ) {
5585 const { data } = event
5686 if ( ! data ?. type ?. startsWith ( "flowindex_" ) ) return
@@ -60,18 +90,22 @@ export function createFlowDevWalletProvider(config: FlowDevWalletConfig = {}) {
6090 if ( data . address ) {
6191 connectedAddress = data . address
6292 chainId = data . chainId
93+ persistSession ( )
6394 }
6495 const resolvers = readyResolvers
6596 readyResolvers = [ ]
6697 resolvers . forEach ( ( r ) => r ( ) )
6798 }
6899
69100 if ( data . type === "flowindex_connected" ) {
70- connectedAddress = data . address
101+ const address = data . address as string
102+ connectedAddress = address
71103 chainId = data . chainId
72104 popupReady = true
105+ persistSession ( )
73106 emit ( "connect" , { chainId : `0x${ chainId ! . toString ( 16 ) } ` } )
74- emit ( "accountsChanged" , [ connectedAddress ] )
107+ emit ( "accountsChanged" , [ address ] )
108+ resolveConnectWaiters ( [ address ] )
75109 const resolvers = readyResolvers
76110 readyResolvers = [ ]
77111 resolvers . forEach ( ( r ) => r ( ) )
@@ -81,6 +115,8 @@ export function createFlowDevWalletProvider(config: FlowDevWalletConfig = {}) {
81115 connectedAddress = null
82116 chainId = null
83117 popupReady = false
118+ persistSession ( )
119+ rejectConnectWaiters ( new Error ( "User rejected connection" ) )
84120 emit ( "disconnect" , { code : 4900 , message : "Disconnected" } )
85121 emit ( "accountsChanged" , [ ] )
86122 }
@@ -144,26 +180,25 @@ export function createFlowDevWalletProvider(config: FlowDevWalletConfig = {}) {
144180 if ( method === "eth_requestAccounts" ) {
145181 if ( connectedAddress ) return [ connectedAddress ]
146182
147- openPopup ( )
148-
149183 return new Promise < string [ ] > ( ( resolve , reject ) => {
184+ const waiter = {
185+ resolve : ( accounts : string [ ] ) => {
186+ clearTimeout ( timeout )
187+ resolve ( accounts )
188+ } ,
189+ reject : ( error : Error ) => {
190+ clearTimeout ( timeout )
191+ reject ( error )
192+ } ,
193+ }
150194 const timeout = setTimeout ( ( ) => {
195+ connectWaiters = connectWaiters . filter ( ( candidate ) => candidate !== waiter )
151196 reject ( new Error ( "Connection timed out" ) )
152197 } , 120_000 )
153198
154- const handler = ( event : MessageEvent ) => {
155- if ( event . data ?. type === "flowindex_connected" ) {
156- clearTimeout ( timeout )
157- window . removeEventListener ( "message" , handler )
158- resolve ( [ event . data . address ] )
159- }
160- if ( event . data ?. type === "flowindex_disconnected" ) {
161- clearTimeout ( timeout )
162- window . removeEventListener ( "message" , handler )
163- reject ( new Error ( "User rejected connection" ) )
164- }
165- }
166- window . addEventListener ( "message" , handler )
199+ connectWaiters . push ( waiter )
200+
201+ openPopup ( )
167202 } )
168203 }
169204
@@ -205,6 +240,7 @@ export function createFlowDevWalletProvider(config: FlowDevWalletConfig = {}) {
205240 connectedAddress = null
206241 chainId = null
207242 popupReady = false
243+ persistSession ( )
208244 if ( popup && ! popup . closed ) popup . close ( )
209245 popup = null
210246 emit ( "disconnect" , { code : 4900 , message : "Disconnected" } )
@@ -216,3 +252,27 @@ export function createFlowDevWalletProvider(config: FlowDevWalletConfig = {}) {
216252}
217253
218254export type FlowDevWalletProvider = ReturnType < typeof createFlowDevWalletProvider >
255+
256+ function getSessionStorageKey ( walletUrl : string ) : string {
257+ const normalizedWalletUrl = typeof window !== "undefined"
258+ ? new URL ( walletUrl , window . location . href ) . toString ( )
259+ : walletUrl
260+ return `flow-dev-wallet:session:${ normalizedWalletUrl } `
261+ }
262+
263+ function readPersistedSession ( storageKey : string ) : PersistedSession | null {
264+ if ( typeof window === "undefined" ) return null
265+
266+ try {
267+ const raw = window . localStorage . getItem ( storageKey )
268+ if ( ! raw ) return null
269+ const parsed = JSON . parse ( raw ) as PersistedSession
270+ if ( ! parsed ?. connectedAddress ) return null
271+ return {
272+ connectedAddress : parsed . connectedAddress ,
273+ chainId : typeof parsed . chainId === "number" ? parsed . chainId : null ,
274+ }
275+ } catch {
276+ return null
277+ }
278+ }
0 commit comments