apiClient
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
/* global PublicKeyCredentialCreationOptions, PublicKeyCredentialRequestOptions */
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Navigate, useLocation } from 'react-router-dom';
|
||||
import LoginView from '../login/LoginView';
|
||||
@@ -9,7 +10,15 @@ import {
|
||||
serializeAuthenticationCredential,
|
||||
serializeRegistrationCredential,
|
||||
} from '../utils/webauthn';
|
||||
import { api, useAppDispatch, useAppState } from './appState';
|
||||
import { useAppDispatch, useAppState } from './appState';
|
||||
import {
|
||||
finishPasskeyLogin,
|
||||
finishSignup,
|
||||
performLogin,
|
||||
selectTenant,
|
||||
startPasskeyLogin,
|
||||
startSignup,
|
||||
} from '../lib/apiClient';
|
||||
|
||||
type StatusVariant = 'info' | 'success' | 'error';
|
||||
|
||||
@@ -28,6 +37,11 @@ interface TenantSelectionState {
|
||||
tenants?: TenantOption[];
|
||||
}
|
||||
|
||||
type AuthResponse = {
|
||||
access_token?: string;
|
||||
tenant?: TenantOption | null;
|
||||
tenants?: TenantOption[];
|
||||
};
|
||||
|
||||
const LoginRoute: React.FC = () => {
|
||||
const appState = useAppState();
|
||||
@@ -161,23 +175,19 @@ const LoginRoute: React.FC = () => {
|
||||
|
||||
try {
|
||||
setSelectingTenantId(tenant.id);
|
||||
const { data } = await api.post(
|
||||
'/auth/select-tenant',
|
||||
const data = await selectTenant(
|
||||
{ tenant_id: tenant.id },
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${tenantSelection.selectionToken}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
tenantSelection.selectionToken,
|
||||
) as AuthResponse;
|
||||
|
||||
if (!data?.access_token) {
|
||||
const accessToken = data?.access_token;
|
||||
if (!accessToken) {
|
||||
throw new Error('Invalid tenant selection response.');
|
||||
}
|
||||
|
||||
appDispatch({
|
||||
type: 'LOGIN_SUCCESS',
|
||||
token: data.access_token,
|
||||
token: accessToken,
|
||||
tenant: data.tenant || null,
|
||||
});
|
||||
setStatusMessage('Login successful.', 'success');
|
||||
@@ -211,9 +221,9 @@ const LoginRoute: React.FC = () => {
|
||||
setPasskeyLoading(true);
|
||||
appDispatch({ type: 'LOGIN_REQUEST' });
|
||||
try {
|
||||
const { data: startData } = await api.post('/auth/passkeys/login/start', { username });
|
||||
const challengeId = startData.challengeId;
|
||||
const publicKeyOptions = startData.publicKey;
|
||||
const startData = await startPasskeyLogin(username);
|
||||
const challengeId = (startData as { challengeId?: string })?.challengeId;
|
||||
const publicKeyOptions = (startData as { publicKey?: PublicKeyCredentialRequestOptions })?.publicKey;
|
||||
|
||||
if (!challengeId || !publicKeyOptions) {
|
||||
throw new Error('Invalid passkey challenge response.');
|
||||
@@ -239,13 +249,13 @@ const LoginRoute: React.FC = () => {
|
||||
credential: serialized,
|
||||
};
|
||||
|
||||
const { data: finishData } = await api.post('/auth/passkeys/login/finish', finishPayload);
|
||||
const finishData = await finishPasskeyLogin(finishPayload) as AuthResponse;
|
||||
|
||||
if (finishData?.access_token && Array.isArray(finishData?.tenants)) {
|
||||
if (finishData?.access_token && Array.isArray(finishData.tenants)) {
|
||||
appDispatch({
|
||||
type: 'TENANT_SELECTION_REQUIRED',
|
||||
selectionToken: finishData.access_token,
|
||||
tenants: finishData.tenants,
|
||||
tenants: finishData.tenants || [],
|
||||
});
|
||||
setStatusMessage('Select a tenant to continue.', 'info');
|
||||
return;
|
||||
@@ -322,16 +332,16 @@ const LoginRoute: React.FC = () => {
|
||||
payload.preferred_tenant_id = magicPreferredTenantId;
|
||||
}
|
||||
|
||||
const { data } = await api.post('/auth/login', payload);
|
||||
const data = await performLogin(payload) as AuthResponse;
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data?.access_token && Array.isArray(data?.tenants)) {
|
||||
if (data?.access_token && Array.isArray(data.tenants)) {
|
||||
appDispatch({
|
||||
type: 'TENANT_SELECTION_REQUIRED',
|
||||
selectionToken: data.access_token,
|
||||
tenants: data.tenants,
|
||||
tenants: data.tenants || [],
|
||||
});
|
||||
setStatusMessage('Select a tenant to continue.', 'info');
|
||||
return;
|
||||
@@ -416,7 +426,10 @@ const LoginRoute: React.FC = () => {
|
||||
|
||||
setSignupLoading(true);
|
||||
try {
|
||||
const { data: startData } = await api.post('/auth/signup/start', { username });
|
||||
const startData = await startSignup(username) as {
|
||||
signup_token?: string;
|
||||
challenge?: { challengeId?: string; publicKey?: PublicKeyCredentialCreationOptions };
|
||||
};
|
||||
const signupToken = startData.signup_token;
|
||||
const challengePayload = startData.challenge;
|
||||
const challengeId = challengePayload?.challengeId;
|
||||
@@ -446,13 +459,13 @@ const LoginRoute: React.FC = () => {
|
||||
credential: serialized,
|
||||
};
|
||||
|
||||
const { data: finishData } = await api.post('/auth/signup/finish', finishPayload);
|
||||
const finishData = await finishSignup(finishPayload) as AuthResponse;
|
||||
|
||||
if (finishData?.access_token && Array.isArray(finishData?.tenants)) {
|
||||
if (finishData?.access_token && Array.isArray(finishData.tenants)) {
|
||||
appDispatch({
|
||||
type: 'TENANT_SELECTION_REQUIRED',
|
||||
selectionToken: finishData.access_token,
|
||||
tenants: finishData.tenants,
|
||||
tenants: finishData.tenants || [],
|
||||
});
|
||||
setStatusMessage('Select a tenant to continue.', 'info');
|
||||
return;
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useAppShell } from '../appShellContext';
|
||||
import useApiTokens from '../settings/useApiTokens';
|
||||
import useCapabilitySets from '../settings/useCapabilitySets';
|
||||
import useCapabilities from '../settings/useCapabilities';
|
||||
import { api } from './appState';
|
||||
|
||||
interface SettingsRouteProps {
|
||||
open?: boolean;
|
||||
@@ -38,7 +37,7 @@ const SettingsRoute: React.FC<SettingsRouteProps> = ({ open = true, onClose }) =
|
||||
revoke: revokeToken,
|
||||
regenerate: regenerateToken,
|
||||
dismissSecret,
|
||||
} = useApiTokens({ api, token, notifyApiError, setStatusMessage });
|
||||
} = useApiTokens({ token, notifyApiError, setStatusMessage });
|
||||
|
||||
const {
|
||||
capabilitySets,
|
||||
@@ -51,7 +50,7 @@ const SettingsRoute: React.FC<SettingsRouteProps> = ({ open = true, onClose }) =
|
||||
createCapabilitySet,
|
||||
updateCapabilitySet,
|
||||
deleteCapabilitySet,
|
||||
} = useCapabilitySets({ api, token, notifyApiError, setStatusMessage });
|
||||
} = useCapabilitySets({ token, notifyApiError, setStatusMessage });
|
||||
|
||||
const {
|
||||
capabilities,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useContext, useEffect, useMemo, useReducer } from 'react';
|
||||
import api from '../lib/api';
|
||||
import { listTenants } from '../lib/apiClient';
|
||||
|
||||
type Tenant = Record<string, unknown> | null;
|
||||
|
||||
@@ -217,11 +218,11 @@ const AppStateProvider: React.FC<{ children?: React.ReactNode }> = ({ children }
|
||||
}
|
||||
|
||||
try {
|
||||
const { data } = await api.get('/tenants');
|
||||
if (!abort) {
|
||||
const tenants = await listTenants();
|
||||
dispatch({
|
||||
type: 'SET_TENANTS',
|
||||
tenants: Array.isArray(data?.tenants) ? data.tenants : [],
|
||||
tenants,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user