feat: register T1 (pending, verify)

This commit is contained in:
fsylvain committed 2026-09-26 04:56:48 +02:00
1 parent 3c3f7c6194
commit 4e41d60142
29 files changed
+2162 -42

No files matched your search

@@ -129,6 +129,26 @@ describe('useApi global 401/403/429/offline handling', () => {
},
)
it('A 403 with onForbidden passthrough never redirects even when the session is unverified', async () => {
const session = useSessionStore()
session.session = { verified: false }
session.status = 'ready'
await router.push('/login')
const pathBefore = router.currentRoute.value.fullPath
fetchMock.mockResolvedValue(mockResponse(403))
const call = useApi().request('/v1/auth/register', {
method: 'DELETE',
onForbidden: 'passthrough',
})
await expectApiError(call, { status: 403 })
await settle()
expect(router.currentRoute.value.fullPath).toBe(pathBefore)
expect(session.session).toEqual({ verified: false })
})
it('A 429 on a rate-limited endpoint exposes the Retry-After seconds', async () => {
fetchMock.mockResolvedValue(mockResponse(429, null, { 'Retry-After': '30' }))
+4 -2
View File
@@ -24,9 +24,11 @@ export interface MeResult {
}
export type OnUnauthorized = 'redirect' | 'passthrough'
export type OnForbidden = 'redirect' | 'passthrough'
export interface RequestOptions extends RequestInit {
onUnauthorized?: OnUnauthorized
onForbidden?: OnForbidden
}
export const isOffline = ref(false)
@@ -58,7 +60,7 @@ if (typeof window !== 'undefined') {
export function useApi() {
async function request<T>(path: string, options: RequestOptions = {}): Promise<T> {
const { onUnauthorized = 'redirect', ...init } = options
const { onUnauthorized = 'redirect', onForbidden = 'redirect', ...init } = options
let response: Response
try {
@@ -80,7 +82,7 @@ export function useApi() {
if (response.status === 403) {
const session = useSessionStore()
if (session.session?.verified === false) {
if (onForbidden !== 'passthrough' && session.session?.verified === false) {
router.push('/register/pending')
}
throw new ApiError(403)