All files / shared/types/api login.ts

100% Statements 6/6
100% Branches 0/0
100% Functions 0/0
100% Lines 6/6

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146                42x                                                                 42x                                         42x                   42x                                   42x                                                     42x                                                        
import { z } from "zod";
import { StoredEmailSchema } from "shared/constants/validation";
import { ApiError, ApiResult } from "shared/types/api/errors";
import { EventLogItem } from "shared/types/models/eventLog";
import { UserGroup } from "shared/types/models/user";
 
// POST login
 
export const PostLoginRequestSchema = z.object({
  username: z.string(),
  // Trim to match registration/password-update, which store the trimmed password — otherwise
  // a trailing/leading space typed at login would never match the stored hash
  password: z.string().trim().min(1),
});
 
export type PostLoginRequest = z.infer<typeof PostLoginRequestSchema>;
 
export interface PostLoginResult extends ApiResult {
  groupCode: string;
  isGroupCreator: boolean;
  jwt: string;
  serial: string;
  userGroup: UserGroup;
  username: string;
  eventLogItems: EventLogItem[];
  kompassiUsernameAccepted: boolean;
  // The Kompassi OIDC `sub` claim, or "" for a local account. Opaque: Kompassi
  // makes no promises about its format
  kompassiId: string;
  email: string;
  emailNotificationPermitAsked: boolean;
}
 
interface PostLoginError extends ApiError {
  errorId: "unknown" | "loginFailed" | "loginDisabled";
}
 
export type PostLoginResponse = PostLoginResult | PostLoginError;
 
// POST session recovery
 
export const PostSessionRecoveryRequestSchema = z.object({ jwt: z.string() });
 
export type PostSessionRecoveryRequest = z.infer<
  typeof PostSessionRecoveryRequestSchema
>;
 
// Same success shape as a login, but the failures differ: recovery can fail
// because the stored token itself is unusable, which a login can't. Keeping
// that out of PostLoginError spares the login paths a case they never see
export interface PostSessionRecoveryError extends ApiError {
  errorId: "unknown" | "loginFailed" | "loginDisabled" | "sessionExpired";
}
 
export type PostSessionRecoveryResponse =
  | PostLoginResult
  | PostSessionRecoveryError;
 
// POST Kompassi login redirect
 
// The client generates the OAuth state and keeps its own copy, so the server
// stays stateless and any instance can build the authorization URL
export const PostKompassiLoginRedirectRequestSchema = z.object({
  state: z.string().min(1),
});
 
export type PostKompassiLoginRedirectRequest = z.infer<
  typeof PostKompassiLoginRedirectRequestSchema
>;
 
// POST Kompassi login
 
export const PostKompassiLoginRequestSchema = z.object({ code: z.string() });
 
export type PostKompassiLoginRequest = z.infer<
  typeof PostKompassiLoginRequestSchema
>;
 
type PostKompassiLoginResult = PostLoginResult;
 
interface PostKompassiLoginError extends ApiError {
  errorId: "unknown" | "loginFailed" | "loginDisabled" | "invalidUserGroup";
}
 
export type PostKompassiLoginResponse =
  | PostKompassiLoginResult
  | PostKompassiLoginError;
 
// POST Verify Kompassi login
 
export const PostVerifyKompassiLoginRequestSchema = z.object({
  username: z.string().trim(),
});
 
export type PostVerifyKompassiLoginRequest = z.infer<
  typeof PostVerifyKompassiLoginRequestSchema
>;
 
export interface PostVerifyKompassiLoginPayload {
  username: string;
  kompassiUsernameAccepted: boolean;
  jwt: string;
}
 
export type PostVerifyKompassiLoginResult = PostVerifyKompassiLoginPayload &
  ApiResult;
 
export interface PostVerifyKompassiLoginError extends ApiError {
  errorId: "unknown" | "usernameNotFree" | "loginFailed";
}
 
export type PostVerifyKompassiLoginResponse =
  | PostVerifyKompassiLoginResult
  | PostVerifyKompassiLoginError;
 
// POST Update user email address
 
export const PostUpdateUserEmailAddressRequestSchema = z.object({
  email: z.string().trim().pipe(StoredEmailSchema),
});
 
export type PostUpdateUserEmailAddressRequest = z.infer<
  typeof PostUpdateUserEmailAddressRequestSchema
>;
 
interface PostUpdateUserEmailAddressPayload {
  email: string;
  emailNotificationPermitAsked: boolean;
  jwt: string;
}
 
type PostUpdateUserEmailAddressResult = PostUpdateUserEmailAddressPayload &
  ApiResult;
 
interface PostUpdateUserEmailAddressError extends ApiError {
  errorId: "unknown" | "invalidEmail";
}
 
export type PostUpdateUserEmailAddressResponse =
  | PostUpdateUserEmailAddressResult
  | PostUpdateUserEmailAddressError;
 
// Finalize login
 
export type PostFinalizeLogin = PostUpdateUserEmailAddressPayload;