Skip to content

Commit b5c8420

Browse files
committed
feat(auth): address Copilot review findings for uvdsl migration
- Convert `SessionWithLegacyEvents` imports to type-only imports to avoid runtime side effects when importing auth-related modules - Prevent eager initialization of `authSession` via type-only usage in: - types.ts - SolidAuthnLogic.ts - solidLogic.ts - Add focused tests for fetch bridge behavior in `solidLogicSingleton`: - use `window.fetch` when `credentials: omit` - fall back to `authFetch` when `session.fetch` is unavailable - Keep migration compatibility behavior intact while improving import safety and regression coverage
1 parent cc582ca commit b5c8420

4 files changed

Lines changed: 62 additions & 5 deletions

File tree

src/authn/SolidAuthnLogic.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { namedNode, NamedNode, sym } from 'rdflib'
22
import { appContext, offlineTestID } from './authUtil'
33
import * as debug from '../util/debug'
4-
import { SessionWithLegacyEvents } from '../authSession/authSession'
5-
import { AuthenticationContext, AuthnLogic } from '../types'
4+
import type { SessionWithLegacyEvents } from '../authSession/authSession'
5+
import type { AuthenticationContext, AuthnLogic } from '../types'
66

77
export class SolidAuthnLogic implements AuthnLogic {
88
private session: SessionWithLegacyEvents

src/logic/solidLogic.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import * as rdf from 'rdflib'
22
import { LiveStore, NamedNode, Statement } from 'rdflib'
33
import { createAclLogic } from '../acl/aclLogic'
44
import { SolidAuthnLogic } from '../authn/SolidAuthnLogic'
5-
import { SessionWithLegacyEvents } from '../authSession/authSession'
5+
import type { SessionWithLegacyEvents } from '../authSession/authSession'
66
import { createChatLogic } from '../chat/chatLogic'
77
import { createInboxLogic } from '../inbox/inboxLogic'
88
import { createProfileLogic } from '../profile/profileLogic'
99
import { createTypeIndexLogic } from '../typeIndex/typeIndexLogic'
1010
import { createContainerLogic } from '../util/containerLogic'
1111
import { createUtilityLogic } from '../util/utilityLogic'
12-
import { AuthnLogic, SolidLogic } from '../types'
12+
import type { AuthnLogic, SolidLogic } from '../types'
1313
import * as debug from '../util/debug'
1414
/*
1515
** It is important to distinquish `fetch`, a function provided by the browser

src/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SessionWithLegacyEvents } from './authSession/authSession'
1+
import type { SessionWithLegacyEvents } from './authSession/authSession'
22
import { LiveStore, NamedNode, Statement } from 'rdflib'
33

44
export type AppDetails = {

test/logic.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { solidLogicSingleton } from '../src/logic/solidLogicSingleton'
2+
import { authSession } from '../src/authSession/authSession'
3+
import fetchMock from 'jest-fetch-mock'
24
import { silenceDebugMessages } from './helpers/debugger'
35

46
silenceDebugMessages()
@@ -27,3 +29,58 @@ describe('authn', () => {
2729
})
2830
})
2931

32+
describe('solidLogicSingleton fetch bridge', () => {
33+
const singletonFetch = (solidLogicSingleton.store.fetcher as any)._fetch as (url: string, init?: RequestInit) => Promise<Response>
34+
35+
let originalFetch: any
36+
let originalAuthFetch: any
37+
let originalWebId: any
38+
let originalInfo: any
39+
40+
beforeEach(() => {
41+
fetchMock.resetMocks()
42+
43+
const sessionAny = authSession as any
44+
originalFetch = sessionAny.fetch
45+
originalAuthFetch = sessionAny.authFetch
46+
originalWebId = sessionAny.webId
47+
originalInfo = sessionAny.info
48+
49+
sessionAny.webId = undefined
50+
sessionAny.info = { isLoggedIn: false }
51+
})
52+
53+
afterEach(() => {
54+
const sessionAny = authSession as any
55+
sessionAny.fetch = originalFetch
56+
sessionAny.authFetch = originalAuthFetch
57+
sessionAny.webId = originalWebId
58+
sessionAny.info = originalInfo
59+
})
60+
61+
it('uses window.fetch when credentials are omit even if a session exists', async () => {
62+
const sessionAny = authSession as any
63+
sessionAny.webId = 'https://alice.example/profile#me'
64+
sessionAny.fetch = jest.fn().mockResolvedValue(new Response('session'))
65+
66+
fetchMock.mockResponseOnce('window')
67+
68+
await singletonFetch('https://example.com/resource', { credentials: 'omit' })
69+
70+
expect(sessionAny.fetch).not.toHaveBeenCalled()
71+
expect(fetchMock).toHaveBeenCalledTimes(1)
72+
})
73+
74+
it('falls back to authFetch when session.fetch is unavailable', async () => {
75+
const sessionAny = authSession as any
76+
sessionAny.webId = 'https://alice.example/profile#me'
77+
sessionAny.fetch = undefined
78+
sessionAny.authFetch = jest.fn().mockResolvedValue(new Response('auth'))
79+
80+
await singletonFetch('https://example.com/resource')
81+
82+
expect(sessionAny.authFetch).toHaveBeenCalledTimes(1)
83+
expect(fetchMock).not.toHaveBeenCalled()
84+
})
85+
})
86+

0 commit comments

Comments
 (0)