From 607f0647a282d507f18670bb8fd726520dd0c520 Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Mon, 16 Mar 2026 07:35:01 +1100 Subject: [PATCH 01/18] fix 403 error when logged in --- src/login/login.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/login/login.ts b/src/login/login.ts index b93e07f11..d4b5e88be 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -180,15 +180,31 @@ export async function ensureLoadedProfile ( if (context.publicProfile) { return context } // already done + let logInContext: AuthenticationContext | undefined try { - const logInContext = await ensureLoggedIn(context) + logInContext = await ensureLoggedIn(context) if (!logInContext.me) { throw new Error('Could not log in') } context.publicProfile = await loadProfile(logInContext.me) } catch (err) { + const message = err instanceof Error ? err.message : `${err}` + const loggedInUser = logInContext && logInContext.me + const isNonFatalProfileSideLoadFailure = + !!loggedInUser && + ( + err instanceof CrossOriginForbiddenError || + err instanceof SameOriginForbiddenError || + /status:\s*403|forbidden/i.test(message) || + /cancel/i.test(message) + ) + if (isNonFatalProfileSideLoadFailure) { + debug.warn(`Unable to load all profile-linked resources; continuing as logged in user: ${message}`) + context.publicProfile = loggedInUser!.doc() + return context + } if (context.div && context.dom) { - context.div.appendChild(widgets.errorMessageBlock(context.dom, err.message)) + context.div.appendChild(widgets.errorMessageBlock(context.dom, message)) } throw new Error(`Can't log in: ${err}`) } From 64151b4c6ab75361f73c033474eee396c43c5ec3 Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Mon, 16 Mar 2026 07:45:12 +1100 Subject: [PATCH 02/18] change 401 not logged in to a msg --- src/login/login.ts | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/login/login.ts b/src/login/login.ts index d4b5e88be..81266538f 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -134,10 +134,13 @@ export async function ensureLoadedPreferences ( context.preferencesFile = preferencesFile } catch (err) { let m2: string - if (err instanceof UnauthorizedError) { + const errorMessage = err instanceof Error ? err.message : `${err}` + if (err instanceof UnauthorizedError || /status:\s*401|unauthorized/i.test(errorMessage)) { m2 = - 'Oops — you are not authenticated (properly logged in), so SolidOS cannot read your preferences file. Try logging out and then logging back in.' - alert(m2) + 'Not logged in, so preferences were not loaded.' + context.preferencesFileError = m2 + debug.warn(m2) + return context } else if (err instanceof CrossOriginForbiddenError) { m2 = `Unauthorized: Assuming preference file blocked for origin ${window.location.origin}` context.preferencesFileError = m2 @@ -184,11 +187,24 @@ export async function ensureLoadedProfile ( try { logInContext = await ensureLoggedIn(context) if (!logInContext.me) { - throw new Error('Could not log in') + const notLoggedInMessage = 'Not logged in, so profile was not loaded.' + debug.log(notLoggedInMessage) + if (context.div && context.dom) { + context.div.appendChild(widgets.errorMessageBlock(context.dom, notLoggedInMessage)) + } + return context } context.publicProfile = await loadProfile(logInContext.me) } catch (err) { const message = err instanceof Error ? err.message : `${err}` + if (/status:\s*401|unauthorized/i.test(message)) { + const notLoggedInMessage = 'Not logged in, so profile was not loaded.' + debug.warn(notLoggedInMessage) + if (context.div && context.dom) { + context.div.appendChild(widgets.errorMessageBlock(context.dom, notLoggedInMessage)) + } + return context + } const loggedInUser = logInContext && logInContext.me const isNonFatalProfileSideLoadFailure = !!loggedInUser && From 55a2c05b6df03c341be0c8132353b8d5ab8333bb Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Mon, 16 Mar 2026 10:02:05 +1100 Subject: [PATCH 03/18] added break after 403 --- src/login/login.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/login/login.ts b/src/login/login.ts index 81266538f..51317146d 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -211,7 +211,7 @@ export async function ensureLoadedProfile ( ( err instanceof CrossOriginForbiddenError || err instanceof SameOriginForbiddenError || - /status:\s*403|forbidden/i.test(message) || + /status:\s*403\b|forbidden/i.test(message) || /cancel/i.test(message) ) if (isNonFatalProfileSideLoadFailure) { From 4fe6ab29c2f4e79b432db1a2f497b65797b13a54 Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 09:57:36 +1000 Subject: [PATCH 04/18] fix lint error --- test/unit/widgets/forms/index.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/widgets/forms/index.test.ts b/test/unit/widgets/forms/index.test.ts index 93bc1f665..df4a59b39 100644 --- a/test/unit/widgets/forms/index.test.ts +++ b/test/unit/widgets/forms/index.test.ts @@ -609,7 +609,7 @@ describe('buildCheckboxForm', () => { const updateSpy = jest.fn((_deletes, _inserts, callback) => { return new Promise(resolve => { setTimeout(() => { - callback('uri', true, 'ok') + callback(undefined, true, 'ok') resolve(true) }, 0) }) From f27309a1a785fbe6c3cb3f08f7ebae422bc07b5f Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 09:58:53 +1000 Subject: [PATCH 05/18] fix login lint --- src/login/login.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/login/login.ts b/src/login/login.ts index 45c7b3137..d0ff37454 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -1079,11 +1079,11 @@ export function newAppInstance ( * and/or a developer */ export async function getUserRoles (): Promise> { - const sessionInfo = authSession.info + const sessionInfo = authSession.info if (!sessionInfo?.isLoggedIn || !sessionInfo?.webId) { return [] } - + const currentUser = authn.currentUser() if (!currentUser) { return [] From 5dac8db1e731b136720562492167e4c5307d7efc Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 10:12:17 +1000 Subject: [PATCH 06/18] test change --- test/unit/widgets/forms/index.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/widgets/forms/index.test.ts b/test/unit/widgets/forms/index.test.ts index df4a59b39..93bc1f665 100644 --- a/test/unit/widgets/forms/index.test.ts +++ b/test/unit/widgets/forms/index.test.ts @@ -609,7 +609,7 @@ describe('buildCheckboxForm', () => { const updateSpy = jest.fn((_deletes, _inserts, callback) => { return new Promise(resolve => { setTimeout(() => { - callback(undefined, true, 'ok') + callback('uri', true, 'ok') resolve(true) }, 0) }) From 97e32b0d96a90d7bb3da0c315b33bdc33657b3cf Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 10:32:56 +1000 Subject: [PATCH 07/18] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/login/login.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/login/login.ts b/src/login/login.ts index d0ff37454..247513f6d 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -135,7 +135,7 @@ export async function ensureLoadedPreferences ( } catch (err) { let m2: string const errorMessage = err instanceof Error ? err.message : `${err}` - if (err instanceof UnauthorizedError || /status:\s*401|unauthorized/i.test(errorMessage)) { + if (err instanceof UnauthorizedError || /(?:status:\s*401\b|unauthorized)/i.test(errorMessage)) { m2 = 'Not logged in, so preferences were not loaded.' context.preferencesFileError = m2 From ab89cf5cfa0dfe475552ef15c930b2f07ef5433b Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 10:33:33 +1000 Subject: [PATCH 08/18] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/login/login.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/login/login.ts b/src/login/login.ts index 247513f6d..a40600ea7 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -197,7 +197,7 @@ export async function ensureLoadedProfile ( context.publicProfile = await loadProfile(logInContext.me) } catch (err) { const message = err instanceof Error ? err.message : `${err}` - if (/status:\s*401|unauthorized/i.test(message)) { + if (err instanceof UnauthorizedError || /status:\s*401|unauthorized/i.test(message)) { const notLoggedInMessage = 'Not logged in, so profile was not loaded.' debug.warn(notLoggedInMessage) if (context.div && context.dom) { From f49e0fdeb1f13aec0d14d0d8f831c008d3d54a66 Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 10:35:43 +1000 Subject: [PATCH 09/18] dedup logic --- src/login/login.ts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/login/login.ts b/src/login/login.ts index a40600ea7..9e3c6d1fc 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -180,6 +180,15 @@ export async function ensureLoadedPreferences ( export async function ensureLoadedProfile ( context: AuthenticationContext ): Promise { + const handleNotLoggedInProfile = (logMessage: (message: string) => void) => { + const notLoggedInMessage = 'Not logged in, so profile was not loaded.' + logMessage(notLoggedInMessage) + if (context.div && context.dom) { + context.div.appendChild(widgets.errorMessageBlock(context.dom, notLoggedInMessage)) + } + return context + } + if (context.publicProfile) { return context } // already done @@ -187,23 +196,13 @@ export async function ensureLoadedProfile ( try { logInContext = await ensureLoggedIn(context) if (!logInContext.me) { - const notLoggedInMessage = 'Not logged in, so profile was not loaded.' - debug.log(notLoggedInMessage) - if (context.div && context.dom) { - context.div.appendChild(widgets.errorMessageBlock(context.dom, notLoggedInMessage)) - } - return context + return handleNotLoggedInProfile(debug.log) } context.publicProfile = await loadProfile(logInContext.me) } catch (err) { const message = err instanceof Error ? err.message : `${err}` if (err instanceof UnauthorizedError || /status:\s*401|unauthorized/i.test(message)) { - const notLoggedInMessage = 'Not logged in, so profile was not loaded.' - debug.warn(notLoggedInMessage) - if (context.div && context.dom) { - context.div.appendChild(widgets.errorMessageBlock(context.dom, notLoggedInMessage)) - } - return context + return handleNotLoggedInProfile(debug.warn) } const loggedInUser = logInContext && logInContext.me const isNonFatalProfileSideLoadFailure = From 41886e7525785eb69daac959522d4fb8ed225ceb Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 10:42:23 +1000 Subject: [PATCH 10/18] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/login/login.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/login/login.ts b/src/login/login.ts index 9e3c6d1fc..339335ade 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -195,6 +195,12 @@ export async function ensureLoadedProfile ( let logInContext: AuthenticationContext | undefined try { logInContext = await ensureLoggedIn(context) + if (!logInContext.me) { + const webId = authSession?.webId || await authn.checkUser() + if (webId) { + authn.saveUser(webId, logInContext) + } + } if (!logInContext.me) { return handleNotLoggedInProfile(debug.log) } From 1ce28f2d665b619d30a8cc7f75c39dca5ac53690 Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 10:43:14 +1000 Subject: [PATCH 11/18] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/login/login.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/login/login.ts b/src/login/login.ts index 339335ade..6018851da 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -207,7 +207,7 @@ export async function ensureLoadedProfile ( context.publicProfile = await loadProfile(logInContext.me) } catch (err) { const message = err instanceof Error ? err.message : `${err}` - if (err instanceof UnauthorizedError || /status:\s*401|unauthorized/i.test(message)) { + if (err instanceof UnauthorizedError || /(status:\s*401\b|unauthorized)/i.test(message)) { return handleNotLoggedInProfile(debug.warn) } const loggedInUser = logInContext && logInContext.me From 7de7e4c4621dbcc951ffc4748c6497e51002f33a Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 10:43:45 +1000 Subject: [PATCH 12/18] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/login/login.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/login/login.ts b/src/login/login.ts index 6018851da..37e3eed07 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -227,7 +227,11 @@ export async function ensureLoadedProfile ( if (context.div && context.dom) { context.div.appendChild(widgets.errorMessageBlock(context.dom, message)) } - throw new Error(`Can't log in: ${err}`) + const loginError = new Error(`Can't log in: ${message}`) as Error & { cause?: unknown } + if (err instanceof Error) { + loginError.cause = err + } + throw loginError } return context } From c3a16a3a7668a0502f9e78e3a4553f7e661c1761 Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 10:47:48 +1000 Subject: [PATCH 13/18] handle not logged in no repeat --- src/login/login.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/login/login.ts b/src/login/login.ts index 37e3eed07..271241c93 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -182,9 +182,17 @@ export async function ensureLoadedProfile ( ): Promise { const handleNotLoggedInProfile = (logMessage: (message: string) => void) => { const notLoggedInMessage = 'Not logged in, so profile was not loaded.' + const notLoggedInMessageKey = 'not-logged-in-profile' logMessage(notLoggedInMessage) if (context.div && context.dom) { - context.div.appendChild(widgets.errorMessageBlock(context.dom, notLoggedInMessage)) + const existingMessage = context.div.querySelector( + `[data-login-message="${notLoggedInMessageKey}"]` + ) + if (!existingMessage) { + const errorBlock = widgets.errorMessageBlock(context.dom, notLoggedInMessage) + errorBlock.setAttribute('data-login-message', notLoggedInMessageKey) + context.div.appendChild(errorBlock) + } } return context } From 4a9bd3f672c81c71fb32b77b6b3b60c5b47bf50e Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 10:50:09 +1000 Subject: [PATCH 14/18] 401 errors throw --- src/login/login.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/login/login.ts b/src/login/login.ts index 271241c93..c2772c752 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -126,6 +126,12 @@ export async function ensureLoadedPreferences ( try { context = await ensureLoadedProfile(context) + if (!context.me || !context.publicProfile) { + context.preferencesFileError = + context.preferencesFileError || 'Not logged in, so preferences were not loaded.' + return context + } + // console.log('back in Solid UI after logInLoadProfile', context) const preferencesFile = await loadPreferences(context.me as NamedNode) if (progressDisplay) { @@ -833,6 +839,10 @@ export function selectWorkspace ( function displayOptions (context) { // console.log('displayOptions!', context) + if (!context.preferencesFile) { + return + } + async function makeNewWorkspace (_event) { const row = table.appendChild(dom.createElement('tr')) const cell = row.appendChild(dom.createElement('td')) From 0c0c8391f47405c51d21d1d2e81a92889368bafe Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 11:24:15 +1000 Subject: [PATCH 15/18] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/login/login.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/login/login.ts b/src/login/login.ts index c2772c752..61c11b64e 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -210,7 +210,7 @@ export async function ensureLoadedProfile ( try { logInContext = await ensureLoggedIn(context) if (!logInContext.me) { - const webId = authSession?.webId || await authn.checkUser() + const webId = authSession.info?.webId || await authn.checkUser() if (webId) { authn.saveUser(webId, logInContext) } From fd9904a006ab45184541603c0ad1d69b2305de5f Mon Sep 17 00:00:00 2001 From: Sharon Stratsianis Date: Tue, 5 May 2026 11:25:26 +1000 Subject: [PATCH 16/18] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- src/login/login.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/login/login.ts b/src/login/login.ts index 61c11b64e..f1b3531e6 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -840,6 +840,9 @@ export function selectWorkspace ( function displayOptions (context) { // console.log('displayOptions!', context) if (!context.preferencesFile) { + say( + context.preferencesFileError || 'Preferences not available.' + ) return } From 4854ebb6b863e230ec403e0b72daf37bc908eb67 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 5 May 2026 01:28:37 +0000 Subject: [PATCH 17/18] fix: use neutral background for not-logged-in message in handleNotLoggedInProfile Agent-Logs-Url: https://github.com/SolidOS/solid-ui/sessions/b4ca60b7-29b9-4e38-b679-9657c19bc7b0 Co-authored-by: SharonStrats <9412507+SharonStrats@users.noreply.github.com> --- src/login/login.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/login/login.ts b/src/login/login.ts index f1b3531e6..c2d6f6e40 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -195,7 +195,7 @@ export async function ensureLoadedProfile ( `[data-login-message="${notLoggedInMessageKey}"]` ) if (!existingMessage) { - const errorBlock = widgets.errorMessageBlock(context.dom, notLoggedInMessage) + const errorBlock = widgets.errorMessageBlock(context.dom, notLoggedInMessage, 'white') errorBlock.setAttribute('data-login-message', notLoggedInMessageKey) context.div.appendChild(errorBlock) } From f6a51806fc806c8e05c9d334b2b47b8b28d0ad05 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 5 May 2026 01:30:20 +0000 Subject: [PATCH 18/18] fix: set preferencesFileError in all error branches of ensureLoadedPreferences catch block Agent-Logs-Url: https://github.com/SolidOS/solid-ui/sessions/4b8e8c78-2b47-40ca-b1f3-fe0bf78f8017 Co-authored-by: SharonStrats <9412507+SharonStrats@users.noreply.github.com> --- src/login/login.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/login/login.ts b/src/login/login.ts index c2d6f6e40..c37d42244 100644 --- a/src/login/login.ts +++ b/src/login/login.ts @@ -154,16 +154,19 @@ export async function ensureLoadedPreferences ( } else if (err instanceof SameOriginForbiddenError) { m2 = 'You are not authorized to read your preference file. This may be because you are using an untrusted web app.' + context.preferencesFileError = m2 debug.warn(m2) return context } else if (err instanceof NotEditableError) { m2 = 'You are not authorized to edit your preference file. This may be because you are using an untrusted web app.' + context.preferencesFileError = m2 debug.warn(m2) return context } else if (err instanceof WebOperationError) { m2 = 'You are not authorized to edit your preference file. This may be because you are using an untrusted web app.' + context.preferencesFileError = m2 debug.warn(m2) } else if (err instanceof FetchError) { m2 = `Strange: Error ${err.status} trying to read your preference file.${err.message}`