11import { LitElement , html , css } from 'lit'
22import { icons } from '../../../../iconBase'
3- import { authSession } from 'solid-logic'
3+ import { authSession , authn , performServerSideLogout } from 'solid-logic'
44import '../../auth/loginButton/index'
55import '../../auth/signupButton/index'
66import { ifDefined } from 'lit/directives/if-defined.js'
@@ -14,6 +14,36 @@ const DEFAULT_SOLID_ICON_URL = 'https://solidproject.org/assets/img/solid-emblem
1414const DEFAULT_SIGNUP_URL = 'https://solidproject.org/get_a_pod'
1515const DEFAULT_LOGGEDIN_MENU_BUTTON_AVATAR = icons . iconBase + 'emptyProfileAvatar.png'
1616
17+ async function clearPersistedAuthState ( ) : Promise < void > {
18+ if ( typeof window === 'undefined' ) {
19+ return
20+ }
21+
22+ const explicitKeys = [ 'loginIssuer' , 'preLoginRedirectHash' ]
23+ for ( const key of explicitKeys ) {
24+ window . localStorage . removeItem ( key )
25+ window . sessionStorage . removeItem ( key )
26+ }
27+
28+ if ( typeof indexedDB === 'undefined' ) {
29+ return
30+ }
31+
32+ const databases = [ 'soidc' , 'solid-client-authn-store' , 'solid-client-authn' ]
33+ for ( const dbName of databases ) {
34+ await new Promise < void > ( ( resolve ) => {
35+ try {
36+ const request = indexedDB . deleteDatabase ( dbName )
37+ request . onsuccess = ( ) => resolve ( )
38+ request . onerror = ( ) => resolve ( )
39+ request . onblocked = ( ) => resolve ( )
40+ } catch ( _err ) {
41+ resolve ( )
42+ }
43+ } )
44+ }
45+ }
46+
1747export type HeaderAuthState = 'logged-out' | 'logged-in'
1848
1949export type HeaderMenuItem = {
@@ -51,7 +81,8 @@ export class Header extends LitElement {
5181 accountMenuOpen : { state : true } ,
5282 helpMenuOpen : { state : true } ,
5383 hasSlottedAccountMenu : { state : true } ,
54- hasSlottedHelpMenu : { state : true }
84+ hasSlottedHelpMenu : { state : true } ,
85+ authResolved : { state : true }
5586 }
5687
5788 static styles = css `
@@ -514,6 +545,14 @@ export class Header extends LitElement {
514545 declare helpMenuOpen : boolean
515546 declare hasSlottedAccountMenu : boolean
516547 declare hasSlottedHelpMenu : boolean
548+ declare authResolved : boolean
549+ private _refreshPromise : Promise < void > | null = null
550+
551+ private readonly handleAuthSessionChange = ( ) => {
552+ this . refreshAuthStateFromSession ( ) . catch ( ( ) => {
553+ // Keep auth event handling resilient on transient refresh failures.
554+ } )
555+ }
517556
518557 constructor ( ) {
519558 super ( )
@@ -538,20 +577,59 @@ export class Header extends LitElement {
538577 this . helpMenuOpen = false
539578 this . hasSlottedAccountMenu = false
540579 this . hasSlottedHelpMenu = false
580+ this . authResolved = false
541581 }
542582
543583 connectedCallback ( ) {
544584 super . connectedCallback ( )
545585 document . addEventListener ( 'click' , this . handleDocumentClick )
546586 window . addEventListener ( 'keydown' , this . handleWindowKeydown )
587+ if ( typeof authSession . events ?. on === 'function' ) {
588+ authSession . events . on ( 'login' , this . handleAuthSessionChange )
589+ authSession . events . on ( 'logout' , this . handleAuthSessionChange )
590+ authSession . events . on ( 'sessionRestore' , this . handleAuthSessionChange )
591+ }
592+ this . refreshAuthStateFromSession ( ) . catch ( ( ) => {
593+ // Keep initial header render resilient on transient refresh failures.
594+ } )
547595 }
548596
549597 disconnectedCallback ( ) {
550598 document . removeEventListener ( 'click' , this . handleDocumentClick )
551599 window . removeEventListener ( 'keydown' , this . handleWindowKeydown )
600+ if ( typeof authSession . events ?. off === 'function' ) {
601+ authSession . events . off ( 'login' , this . handleAuthSessionChange )
602+ authSession . events . off ( 'logout' , this . handleAuthSessionChange )
603+ authSession . events . off ( 'sessionRestore' , this . handleAuthSessionChange )
604+ }
552605 super . disconnectedCallback ( )
553606 }
554607
608+ private async refreshAuthStateFromSession ( ) {
609+ if ( ! this . _refreshPromise ) {
610+ this . _refreshPromise = ( async ( ) => {
611+ try {
612+ await authn . checkUser ( )
613+ // Some auth stacks resolve session state asynchronously after first check.
614+ if ( ! authn . currentUser ( ) ) {
615+ await authn . checkUser ( )
616+ }
617+ } catch ( _err ) {
618+ // Keep rendering even if session refresh cannot complete.
619+ }
620+ } ) ( )
621+ }
622+
623+ try {
624+ await this . _refreshPromise
625+ } finally {
626+ this . _refreshPromise = null
627+ }
628+
629+ this . authState = authn . currentUser ( ) ? 'logged-in' : 'logged-out'
630+ this . authResolved = true
631+ }
632+
555633 private handleHelpMenuClick ( item : HeaderMenuItem , event : MouseEvent ) {
556634 event . preventDefault ( )
557635 this . helpMenuOpen = false
@@ -669,8 +747,8 @@ export class Header extends LitElement {
669747 `
670748 }
671749
672- private handleLoginSuccess ( ) {
673- this . authState = 'logged-in'
750+ private async handleLoginSuccess ( ) {
751+ await this . refreshAuthStateFromSession ( )
674752 this . dispatchEvent ( new CustomEvent ( 'auth-action-select' , {
675753 detail : { role : 'login' } ,
676754 bubbles : true ,
@@ -680,12 +758,25 @@ export class Header extends LitElement {
680758
681759 private async handleLogout ( ) {
682760 this . accountMenuOpen = false
761+ const issuer = window . localStorage . getItem ( 'loginIssuer' ) || ''
762+
683763 try {
684764 await authSession . logout ( )
685765 } catch ( _err ) {
686766 // logout errors are non-fatal — proceed to clear state
687767 }
688- this . authState = 'logged-out'
768+
769+ await clearPersistedAuthState ( )
770+
771+ const redirectedToServerLogout = await performServerSideLogout ( {
772+ issuer,
773+ postLogoutRedirectPath : '/'
774+ } )
775+ if ( redirectedToServerLogout ) {
776+ return
777+ }
778+
779+ await this . refreshAuthStateFromSession ( )
689780 this . dispatchEvent ( new CustomEvent ( 'logout-select' , {
690781 detail : { role : 'logout' } ,
691782 bubbles : true ,
@@ -802,6 +893,10 @@ export class Header extends LitElement {
802893 `
803894 }
804895
896+ if ( ! this . authResolved ) {
897+ return html `< div class ="auth-actions " part ="auth-actions "> </ div > `
898+ }
899+
805900 if ( this . authState === 'logged-out' ) {
806901 return this . renderLoggedOutActions ( )
807902 }
0 commit comments