85 lines
2.1 KiB
TypeScript

export type AuthRequestMessage =
| { type: "auth:get-state" }
| { type: "auth:sign-in" }
| { type: "auth:sign-out" }
| { type: "auth:get-access-token" };
export interface AuthStateValue {
accessTokenExpiresAt?: number | null;
isAuthenticated: boolean;
lastError?: string | null;
resource?: string | null;
scopes?: string[];
tokenAvailable?: boolean;
userInfo?: {
email?: string;
name?: string;
sub?: string;
username?: string;
} | null;
}
export type AuthResponseMessage =
| { ok: true; type: "auth:state"; value: AuthStateValue }
| { ok: true; type: "auth:token"; value: { accessToken: string } }
| { ok: true; type: "auth:ack" }
| { ok: false; type: "auth:error"; error: string };
const authRequestTypes = new Set<AuthRequestMessage["type"]>([
"auth:get-state",
"auth:sign-in",
"auth:sign-out",
"auth:get-access-token"
]);
export function isAuthRequestMessage(
value: unknown
): value is AuthRequestMessage {
if (!value || typeof value !== "object") {
return false;
}
const candidate = value as Partial<AuthRequestMessage>;
return typeof candidate.type === "string" && authRequestTypes.has(candidate.type);
}
export function isAuthResponseMessage(
value: unknown
): value is AuthResponseMessage {
if (!value || typeof value !== "object") {
return false;
}
const candidate = value as Partial<AuthResponseMessage>;
if (candidate.ok === false) {
return candidate.type === "auth:error" && typeof candidate.error === "string";
}
if (candidate.ok !== true || typeof candidate.type !== "string") {
return false;
}
if (candidate.type === "auth:ack") {
return true;
}
if (candidate.type === "auth:token") {
return Boolean(
candidate.value &&
typeof candidate.value === "object" &&
typeof (candidate.value as { accessToken?: unknown }).accessToken === "string"
);
}
if (candidate.type === "auth:state") {
return Boolean(
candidate.value &&
typeof candidate.value === "object" &&
typeof (candidate.value as { isAuthenticated?: unknown }).isAuthenticated ===
"boolean"
);
}
return false;
}