feat(opsserver-admin): add persisted admin bootstrap flow with optional idp.global authentication

This commit is contained in:
2026-05-14 00:30:09 +00:00
parent 47a1f5d7db
commit 70fcd46d52
14 changed files with 733 additions and 40 deletions
+49
View File
@@ -10,6 +10,8 @@ export interface ILoginState {
isLoggedIn: boolean;
}
export type IAdminBootstrapStatus = interfaces.requests.IReq_GetAdminBootstrapStatus['response'];
export interface IStatsState {
serverStats: interfaces.data.IServerStats | null;
emailStats: interfaces.data.IEmailStats | null;
@@ -312,7 +314,11 @@ export const routeManagementStatePart = await appState.getStatePart<IRouteManage
export interface IUser {
id: string;
username: string;
email?: string;
name?: string;
role: string;
status?: 'active' | 'disabled';
authSources?: Array<'local' | 'idp.global'>;
}
export interface IUsersState {
@@ -351,6 +357,7 @@ const getActionContext = (): IActionContext => {
export const loginAction = loginStatePart.createAction<{
username: string;
password: string;
authSource?: interfaces.requests.TAdminLoginAuthSource;
}>(async (statePartArg, dataArg): Promise<ILoginState> => {
const typedRequest = new plugins.domtools.plugins.typedrequest.TypedRequest<
interfaces.requests.IReq_AdminLoginWithUsernameAndPassword
@@ -360,6 +367,7 @@ export const loginAction = loginStatePart.createAction<{
const response = await typedRequest.fire({
username: dataArg.username,
password: dataArg.password,
authSource: dataArg.authSource,
});
if (response.identity) {
@@ -375,6 +383,47 @@ export const loginAction = loginStatePart.createAction<{
}
});
export async function getAdminBootstrapStatus(): Promise<IAdminBootstrapStatus> {
const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
interfaces.requests.IReq_GetAdminBootstrapStatus
>('/typedrequest', 'getAdminBootstrapStatus');
return request.fire({});
}
export async function createInitialAdminUser(optionsArg: {
email: string;
name?: string;
password: string;
enableIdpGlobalAuth?: boolean;
}) {
const context = getActionContext();
if (!context.identity) {
throw new Error('No identity available for admin bootstrap');
}
const request = new plugins.domtools.plugins.typedrequest.TypedRequest<
interfaces.requests.IReq_CreateInitialAdminUser
>('/typedrequest', 'createInitialAdminUser');
const response = await request.fire({
identity: context.identity,
email: optionsArg.email,
name: optionsArg.name,
password: optionsArg.password,
enableIdpGlobalAuth: optionsArg.enableIdpGlobalAuth,
});
if (response.identity) {
loginStatePart.setState({
identity: response.identity,
isLoggedIn: true,
});
}
return response;
}
// Logout Action — always clears state, even if identity is expired/missing
export const logoutAction = loginStatePart.createAction(async (statePartArg) => {
const context = getActionContext();