feat(web): add authenticated file workflow
- feat: connect login and logout to the REST API with session-scoped tokens, protected routing, single-flight refresh, and authenticated query cache cleanup. - feat: add the Ant Design application shell with root file listing, pagination, small-file upload, and authenticated download. - test: cover session storage and API retry and error behavior with Vitest. - docs: document the browser milestone, same-origin API topology, and deferred transfer and account features.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import { createSessionStore } from './session.ts'
|
||||
import type { TokenPair } from './types.ts'
|
||||
|
||||
class MemoryStorage {
|
||||
private readonly values = new Map<string, string>()
|
||||
|
||||
getItem(key: string) {
|
||||
return this.values.get(key) ?? null
|
||||
}
|
||||
|
||||
removeItem(key: string) {
|
||||
this.values.delete(key)
|
||||
}
|
||||
|
||||
setItem(key: string, value: string) {
|
||||
this.values.set(key, value)
|
||||
}
|
||||
}
|
||||
|
||||
const session: TokenPair = {
|
||||
access_token: 'access-token',
|
||||
refresh_token: 'refresh-token',
|
||||
}
|
||||
|
||||
describe('session store', () => {
|
||||
it('persists and reloads a valid token pair', () => {
|
||||
const storage = new MemoryStorage()
|
||||
const store = createSessionStore(storage)
|
||||
|
||||
store.set(session)
|
||||
|
||||
expect(store.get()).toEqual(session)
|
||||
expect(createSessionStore(storage).get()).toEqual(session)
|
||||
})
|
||||
|
||||
it('notifies subscribers when the session changes', () => {
|
||||
const store = createSessionStore(new MemoryStorage())
|
||||
const listener = vi.fn()
|
||||
const unsubscribe = store.subscribe(listener)
|
||||
|
||||
store.set(session)
|
||||
store.clear()
|
||||
unsubscribe()
|
||||
store.set(session)
|
||||
|
||||
expect(listener).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('discards malformed browser state', () => {
|
||||
const storage = new MemoryStorage()
|
||||
storage.setItem('mygo.auth.session', '{"access_token":true}')
|
||||
|
||||
const store = createSessionStore(storage)
|
||||
|
||||
expect(store.get()).toBeNull()
|
||||
expect(storage.getItem('mygo.auth.session')).toBeNull()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user