fix(login): default lifetime, show expiration on accounts page (#10297)

This PR fixes an issue where the password lifetime was not applied
correctly in certain scenarios.
It also improves the sessions page by providing more information about
expiration and verification timestamps and a mobile layout for clearing
sessions.
<img width="506" height="760" alt="Screenshot 2025-07-22 at 08 56 14"
src="https://github.com/user-attachments/assets/1e621ca2-206c-4931-b27d-9592eebc646e"
/>

Closes https://github.com/zitadel/typescript/issues/481
This commit is contained in:
Max Peintner
2025-07-22 11:18:15 +02:00
committed by GitHub
parent 9b0e5bf714
commit a3e1d6a3ff
23 changed files with 467 additions and 257 deletions

View File

@@ -6,7 +6,9 @@
"title": "Konten", "title": "Konten",
"description": "Wählen Sie das Konto aus, das Sie verwenden möchten.", "description": "Wählen Sie das Konto aus, das Sie verwenden möchten.",
"addAnother": "Ein weiteres Konto hinzufügen", "addAnother": "Ein weiteres Konto hinzufügen",
"noResults": "Keine Konten gefunden" "noResults": "Keine Konten gefunden",
"verified": "verifiziert",
"expired": "abgelaufen"
}, },
"logout": { "logout": {
"title": "Logout", "title": "Logout",

View File

@@ -6,7 +6,9 @@
"title": "Accounts", "title": "Accounts",
"description": "Select the account you want to use.", "description": "Select the account you want to use.",
"addAnother": "Add another account", "addAnother": "Add another account",
"noResults": "No accounts found" "noResults": "No accounts found",
"verified": "verified",
"expired": "expired"
}, },
"logout": { "logout": {
"title": "Logout", "title": "Logout",

View File

@@ -4,9 +4,11 @@
}, },
"accounts": { "accounts": {
"title": "Cuentas", "title": "Cuentas",
"description": "Selecciona la cuenta que deseas usar.", "description": "Seleccione la cuenta que desea utilizar.",
"addAnother": "Agregar otra cuenta", "addAnother": "Agregar otra cuenta",
"noResults": "No se encontraron cuentas" "noResults": "No se encontraron cuentas",
"verified": "verificado",
"expired": "expirado"
}, },
"logout": { "logout": {
"title": "Cerrar sesión", "title": "Cerrar sesión",

View File

@@ -4,9 +4,11 @@
}, },
"accounts": { "accounts": {
"title": "Account", "title": "Account",
"description": "Seleziona l'account che desideri utilizzare.", "description": "Seleziona l'account che vuoi utilizzare.",
"addAnother": "Aggiungi un altro account", "addAnother": "Aggiungi un altro account",
"noResults": "Nessun account trovato" "noResults": "Nessun account trovato",
"verified": "verificato",
"expired": "scaduto"
}, },
"logout": { "logout": {
"title": "Esci", "title": "Esci",

View File

@@ -6,7 +6,9 @@
"title": "Konta", "title": "Konta",
"description": "Wybierz konto, którego chcesz użyć.", "description": "Wybierz konto, którego chcesz użyć.",
"addAnother": "Dodaj kolejne konto", "addAnother": "Dodaj kolejne konto",
"noResults": "Nie znaleziono kont" "noResults": "Nie znaleziono kont",
"verified": "zweryfikowany",
"expired": "wygasł"
}, },
"logout": { "logout": {
"title": "Wyloguj się", "title": "Wyloguj się",

View File

@@ -6,7 +6,9 @@
"title": "Аккаунты", "title": "Аккаунты",
"description": "Выберите аккаунт, который хотите использовать.", "description": "Выберите аккаунт, который хотите использовать.",
"addAnother": "Добавить другой аккаунт", "addAnother": "Добавить другой аккаунт",
"noResults": "Аккаунты не найдены" "noResults": "Аккаунты не найдены",
"verified": "проверенный",
"expired": "истёк"
}, },
"logout": { "logout": {
"title": "Выход", "title": "Выход",

View File

@@ -4,9 +4,11 @@
}, },
"accounts": { "accounts": {
"title": "账户", "title": "账户",
"description": "选择您使用的账户。", "description": "选择您使用的账户。",
"addAnother": "添加另一个账户", "addAnother": "添加另一个账户",
"noResults": "未找到账户" "noResults": "未找到账户",
"verified": "已验证",
"expired": "已过期"
}, },
"logout": { "logout": {
"title": "注销", "title": "注销",

View File

@@ -25,6 +25,7 @@
"dependencies": { "dependencies": {
"@headlessui/react": "^2.1.9", "@headlessui/react": "^2.1.9",
"@heroicons/react": "2.1.3", "@heroicons/react": "2.1.3",
"@radix-ui/react-tooltip": "^1.2.7",
"@tailwindcss/forms": "0.5.7", "@tailwindcss/forms": "0.5.7",
"@vercel/analytics": "^1.2.2", "@vercel/analytics": "^1.2.2",
"@zitadel/client": "latest", "@zitadel/client": "latest",

View File

@@ -15,12 +15,12 @@ import { headers } from "next/headers";
import Link from "next/link"; import Link from "next/link";
async function loadSessions({ serviceUrl }: { serviceUrl: string }) { async function loadSessions({ serviceUrl }: { serviceUrl: string }) {
const ids: (string | undefined)[] = await getAllSessionCookieIds(); const cookieIds = await getAllSessionCookieIds();
if (ids && ids.length) { if (cookieIds && cookieIds.length) {
const response = await listSessions({ const response = await listSessions({
serviceUrl, serviceUrl,
ids: ids.filter((id) => !!id) as string[], ids: cookieIds.filter((id) => !!id) as string[],
}); });
return response?.sessions ?? []; return response?.sessions ?? [];
} else { } else {

View File

@@ -5,6 +5,7 @@ import { LanguageSwitcher } from "@/components/language-switcher";
import { Skeleton } from "@/components/skeleton"; import { Skeleton } from "@/components/skeleton";
import { Theme } from "@/components/theme"; import { Theme } from "@/components/theme";
import { ThemeProvider } from "@/components/theme-provider"; import { ThemeProvider } from "@/components/theme-provider";
import * as Tooltip from "@radix-ui/react-tooltip";
import { Analytics } from "@vercel/analytics/react"; import { Analytics } from "@vercel/analytics/react";
import { Lato } from "next/font/google"; import { Lato } from "next/font/google";
import { ReactNode, Suspense } from "react"; import { ReactNode, Suspense } from "react";
@@ -24,6 +25,7 @@ export default async function RootLayout({
<head /> <head />
<body> <body>
<ThemeProvider> <ThemeProvider>
<Tooltip.Provider>
<Suspense <Suspense
fallback={ fallback={
<div <div
@@ -54,6 +56,7 @@ export default async function RootLayout({
</div> </div>
</LanguageProvider> </LanguageProvider>
</Suspense> </Suspense>
</Tooltip.Provider>
</ThemeProvider> </ThemeProvider>
<Analytics /> <Analytics />
</body> </body>

View File

@@ -12,12 +12,12 @@ import { Organization } from "@zitadel/proto/zitadel/org/v2/org_pb";
import { headers } from "next/headers"; import { headers } from "next/headers";
async function loadSessions({ serviceUrl }: { serviceUrl: string }) { async function loadSessions({ serviceUrl }: { serviceUrl: string }) {
const ids: (string | undefined)[] = await getAllSessionCookieIds(); const cookieIds = await getAllSessionCookieIds();
if (ids && ids.length) { if (cookieIds && cookieIds.length) {
const response = await listSessions({ const response = await listSessions({
serviceUrl, serviceUrl,
ids: ids.filter((id) => !!id) as string[], ids: cookieIds.filter((id) => !!id) as string[],
}); });
return response?.sessions ?? []; return response?.sessions ?? [];
} else { } else {

View File

@@ -41,17 +41,13 @@ export default async function Page(props: {
const { method } = params; const { method } = params;
const session = sessionId const session = sessionId
? await loadSessionById(serviceUrl, sessionId, organization) ? await loadSessionById(sessionId, organization)
: await loadMostRecentSession({ : await loadMostRecentSession({
serviceUrl, serviceUrl,
sessionParams: { loginName, organization }, sessionParams: { loginName, organization },
}); });
async function loadSessionById( async function loadSessionById(sessionId: string, organization?: string) {
host: string,
sessionId: string,
organization?: string,
) {
const recent = await getSessionCookieById({ sessionId, organization }); const recent = await getSessionCookieById({ sessionId, organization });
return getSession({ return getSession({
serviceUrl, serviceUrl,

View File

@@ -66,7 +66,6 @@ export default async function Page(props: {
error = err; error = err;
}); });
} else if (method === "sms") { } else if (method === "sms") {
// does not work
await addOTPSMS({ await addOTPSMS({
serviceUrl, serviceUrl,
userId: session.factors.user.id, userId: session.factors.user.id,
@@ -74,7 +73,6 @@ export default async function Page(props: {
error = new Error("Could not add OTP via SMS"); error = new Error("Could not add OTP via SMS");
}); });
} else if (method === "email") { } else if (method === "email") {
// works
await addOTPEmail({ await addOTPEmail({
serviceUrl, serviceUrl,
userId: session.factors.user.id, userId: session.factors.user.id,
@@ -106,6 +104,7 @@ export default async function Page(props: {
paramsToContinue.append("requestId", requestId); paramsToContinue.append("requestId", requestId);
} }
urlToContinue = `/otp/${method}?` + paramsToContinue; urlToContinue = `/otp/${method}?` + paramsToContinue;
// immediately check the OTP on the next page if sms or email was set up // immediately check the OTP on the next page if sms or email was set up
if (["email", "sms"].includes(method)) { if (["email", "sms"].includes(method)) {
return redirect(urlToContinue); return redirect(urlToContinue);

View File

@@ -3,6 +3,7 @@
import { sendLoginname } from "@/lib/server/loginname"; import { sendLoginname } from "@/lib/server/loginname";
import { clearSession, continueWithSession } from "@/lib/server/session"; import { clearSession, continueWithSession } from "@/lib/server/session";
import { XCircleIcon } from "@heroicons/react/24/outline"; import { XCircleIcon } from "@heroicons/react/24/outline";
import * as Tooltip from "@radix-ui/react-tooltip";
import { Timestamp, timestampDate } from "@zitadel/client"; import { Timestamp, timestampDate } from "@zitadel/client";
import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb"; import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb";
import moment from "moment"; import moment from "moment";
@@ -10,6 +11,7 @@ import { useLocale } from "next-intl";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useState } from "react"; import { useState } from "react";
import { Avatar } from "./avatar"; import { Avatar } from "./avatar";
import { Translated } from "./translated";
export function isSessionValid(session: Partial<Session>): { export function isSessionValid(session: Partial<Session>): {
valid: boolean; valid: boolean;
@@ -66,6 +68,8 @@ export function SessionItem({
const router = useRouter(); const router = useRouter();
return ( return (
<Tooltip.Root delayDuration={300}>
<Tooltip.Trigger asChild>
<button <button
onClick={async () => { onClick={async () => {
if (valid && session?.factors?.user) { if (valid && session?.factors?.user) {
@@ -119,12 +123,13 @@ export function SessionItem({
</span> </span>
{valid ? ( {valid ? (
<span className="text-ellipsis text-xs opacity-80"> <span className="text-ellipsis text-xs opacity-80">
<Translated i18nKey="verified" namespace="accounts" />{" "}
{verifiedAt && moment(timestampDate(verifiedAt)).fromNow()} {verifiedAt && moment(timestampDate(verifiedAt)).fromNow()}
</span> </span>
) : ( ) : (
verifiedAt && ( verifiedAt && (
<span className="text-ellipsis text-xs opacity-80"> <span className="text-ellipsis text-xs opacity-80">
expired{" "} <Translated i18nKey="expired" namespace="accounts" />{" "}
{session.expirationDate && {session.expirationDate &&
moment(timestampDate(session.expirationDate)).fromNow()} moment(timestampDate(session.expirationDate)).fromNow()}
</span> </span>
@@ -135,13 +140,13 @@ export function SessionItem({
<span className="flex-grow"></span> <span className="flex-grow"></span>
<div className="relative flex flex-row items-center"> <div className="relative flex flex-row items-center">
{valid ? ( {valid ? (
<div className="absolute right-0 mx-2 h-2 w-2 transform rounded-full bg-green-500 transition-all group-hover:right-6"></div> <div className="absolute right-6 mx-2 h-2 w-2 transform rounded-full bg-green-500 transition-all group-hover:right-6 sm:right-0"></div>
) : ( ) : (
<div className="absolute right-0 mx-2 h-2 w-2 transform rounded-full bg-red-500 transition-all group-hover:right-6"></div> <div className="absolute right-6 mx-2 h-2 w-2 transform rounded-full bg-red-500 transition-all group-hover:right-6 sm:right-0"></div>
)} )}
<XCircleIcon <XCircleIcon
className="hidden h-5 w-5 opacity-50 transition-all hover:opacity-100 group-hover:block" className="h-5 w-5 opacity-50 transition-all hover:opacity-100 group-hover:block sm:hidden"
onClick={(event) => { onClick={(event) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@@ -152,5 +157,18 @@ export function SessionItem({
/> />
</div> </div>
</button> </button>
</Tooltip.Trigger>
{valid && session.expirationDate && (
<Tooltip.Portal>
<Tooltip.Content
className="z-50 select-none rounded-md border bg-background-light-500 px-3 py-2 text-xs text-black shadow-xl dark:border-white/20 dark:bg-background-dark-500 dark:text-white"
sideOffset={5}
>
Expires {moment(timestampDate(session.expirationDate)).fromNow()}
<Tooltip.Arrow className="fill-white dark:fill-white/20" />
</Tooltip.Content>
</Tooltip.Portal>
)}
</Tooltip.Root>
); );
} }

View File

@@ -242,7 +242,7 @@ export async function getSessionCookieByLoginName<T>({
*/ */
export async function getAllSessionCookieIds<T>( export async function getAllSessionCookieIds<T>(
cleanup: boolean = false, cleanup: boolean = false,
): Promise<any> { ): Promise<string[]> {
const cookiesList = await cookies(); const cookiesList = await cookies();
const stringifiedCookie = cookiesList.get("sessions"); const stringifiedCookie = cookiesList.get("sessions");

View File

@@ -55,10 +55,21 @@ export async function createSessionAndUpdateCookie(command: {
const _headers = await headers(); const _headers = await headers();
const { serviceUrl } = getServiceUrlFromHeaders(_headers); const { serviceUrl } = getServiceUrlFromHeaders(_headers);
let sessionLifetime = command.lifetime;
if (!sessionLifetime) {
console.warn("No session lifetime provided, using default of 24 hours.");
sessionLifetime = {
seconds: BigInt(24 * 60 * 60), // 24 hours
nanos: 0,
} as Duration; // for usecases where the lifetime is not specified (user discovery)
}
const createdSession = await createSessionFromChecks({ const createdSession = await createSessionFromChecks({
serviceUrl, serviceUrl,
checks: command.checks, checks: command.checks,
lifetime: command.lifetime, lifetime: sessionLifetime,
}); });
if (createdSession) { if (createdSession) {
@@ -126,11 +137,24 @@ export async function createSessionForIdpAndUpdateCookie({
const _headers = await headers(); const _headers = await headers();
const { serviceUrl } = getServiceUrlFromHeaders(_headers); const { serviceUrl } = getServiceUrlFromHeaders(_headers);
let sessionLifetime = lifetime;
if (!sessionLifetime) {
console.warn(
"No IDP session lifetime provided, using default of 24 hours.",
);
sessionLifetime = {
seconds: BigInt(24 * 60 * 60), // 24 hours
nanos: 0,
} as Duration;
}
const createdSession = await createSessionForUserIdAndIdpIntent({ const createdSession = await createSessionForUserIdAndIdpIntent({
serviceUrl, serviceUrl,
userId, userId,
idpIntent, idpIntent,
lifetime, lifetime: sessionLifetime,
}).catch((error: ErrorDetail | CredentialsCheckError) => { }).catch((error: ErrorDetail | CredentialsCheckError) => {
console.error("Could not set session", error); console.error("Could not set session", error);
if ("failedAttempts" in error && error.failedAttempts) { if ("failedAttempts" in error && error.failedAttempts) {
@@ -190,41 +214,41 @@ export type SessionWithChallenges = Session & {
challenges: Challenges | undefined; challenges: Challenges | undefined;
}; };
export async function setSessionAndUpdateCookie( export async function setSessionAndUpdateCookie(command: {
recentCookie: CustomCookieData, recentCookie: CustomCookieData;
checks?: Checks, checks?: Checks;
challenges?: RequestChallenges, challenges?: RequestChallenges;
requestId?: string, requestId?: string;
lifetime?: Duration, lifetime: Duration;
) { }) {
const _headers = await headers(); const _headers = await headers();
const { serviceUrl } = getServiceUrlFromHeaders(_headers); const { serviceUrl } = getServiceUrlFromHeaders(_headers);
return setSession({ return setSession({
serviceUrl, serviceUrl,
sessionId: recentCookie.id, sessionId: command.recentCookie.id,
sessionToken: recentCookie.token, sessionToken: command.recentCookie.token,
challenges, challenges: command.challenges,
checks, checks: command.checks,
lifetime, lifetime: command.lifetime,
}) })
.then((updatedSession) => { .then((updatedSession) => {
if (updatedSession) { if (updatedSession) {
const sessionCookie: CustomCookieData = { const sessionCookie: CustomCookieData = {
id: recentCookie.id, id: command.recentCookie.id,
token: updatedSession.sessionToken, token: updatedSession.sessionToken,
creationTs: recentCookie.creationTs, creationTs: command.recentCookie.creationTs,
expirationTs: recentCookie.expirationTs, expirationTs: command.recentCookie.expirationTs,
// just overwrite the changeDate with the new one // just overwrite the changeDate with the new one
changeTs: updatedSession.details?.changeDate changeTs: updatedSession.details?.changeDate
? `${timestampMs(updatedSession.details.changeDate)}` ? `${timestampMs(updatedSession.details.changeDate)}`
: "", : "",
loginName: recentCookie.loginName, loginName: command.recentCookie.loginName,
organization: recentCookie.organization, organization: command.recentCookie.organization,
}; };
if (requestId) { if (command.requestId) {
sessionCookie.requestId = requestId; sessionCookie.requestId = command.requestId;
} }
return getSession({ return getSession({

View File

@@ -1,83 +0,0 @@
"use server";
import { setSessionAndUpdateCookie } from "@/lib/server/cookie";
import { create } from "@zitadel/client";
import {
CheckOTPSchema,
ChecksSchema,
CheckTOTPSchema,
} from "@zitadel/proto/zitadel/session/v2/session_service_pb";
import { headers } from "next/headers";
import {
getMostRecentSessionCookie,
getSessionCookieById,
getSessionCookieByLoginName,
} from "../cookies";
import { getServiceUrlFromHeaders } from "../service-url";
import { getLoginSettings } from "../zitadel";
export type SetOTPCommand = {
loginName?: string;
sessionId?: string;
organization?: string;
requestId?: string;
code: string;
method: string;
};
export async function setOTP(command: SetOTPCommand) {
const _headers = await headers();
const { serviceUrl } = getServiceUrlFromHeaders(_headers);
const recentSession = command.sessionId
? await getSessionCookieById({ sessionId: command.sessionId }).catch(
(error) => {
return Promise.reject(error);
},
)
: command.loginName
? await getSessionCookieByLoginName({
loginName: command.loginName,
organization: command.organization,
}).catch((error) => {
return Promise.reject(error);
})
: await getMostRecentSessionCookie().catch((error) => {
return Promise.reject(error);
});
const checks = create(ChecksSchema, {});
if (command.method === "time-based") {
checks.totp = create(CheckTOTPSchema, {
code: command.code,
});
} else if (command.method === "sms") {
checks.otpSms = create(CheckOTPSchema, {
code: command.code,
});
} else if (command.method === "email") {
checks.otpEmail = create(CheckOTPSchema, {
code: command.code,
});
}
const loginSettings = await getLoginSettings({
serviceUrl,
organization: command.organization,
});
return setSessionAndUpdateCookie(
recentSession,
checks,
undefined,
command.requestId,
loginSettings?.secondFactorCheckLifetime,
).then((session) => {
return {
sessionId: session.id,
factors: session.factors,
challenges: session.challenges,
};
});
}

View File

@@ -211,19 +211,27 @@ export async function sendPasskey(command: SendPasskeyCommand) {
organization, organization,
}); });
const lifetime = checks?.webAuthN let lifetime = checks?.webAuthN
? loginSettings?.multiFactorCheckLifetime // TODO different lifetime for webauthn u2f/passkey ? loginSettings?.multiFactorCheckLifetime // TODO different lifetime for webauthn u2f/passkey
: checks?.otpEmail || checks?.otpSms : checks?.otpEmail || checks?.otpSms
? loginSettings?.secondFactorCheckLifetime ? loginSettings?.secondFactorCheckLifetime
: undefined; : undefined;
const session = await setSessionAndUpdateCookie( if (!lifetime) {
recentSession, console.warn("No passkey lifetime provided, defaulting to 24 hours");
lifetime = {
seconds: BigInt(60 * 60 * 24), // default to 24 hours
nanos: 0,
} as Duration;
}
const session = await setSessionAndUpdateCookie({
recentCookie: recentSession,
checks, checks,
undefined,
requestId, requestId,
lifetime, lifetime,
); });
if (!session || !session?.factors?.user?.id) { if (!session || !session?.factors?.user?.id) {
return { error: "Could not update session" }; return { error: "Could not update session" };

View File

@@ -16,7 +16,7 @@ import {
setPassword, setPassword,
setUserPassword, setUserPassword,
} from "@/lib/zitadel"; } from "@/lib/zitadel";
import { ConnectError, create } from "@zitadel/client"; import { ConnectError, create, Duration } from "@zitadel/client";
import { createUserServiceClient } from "@zitadel/client/v2"; import { createUserServiceClient } from "@zitadel/client/v2";
import { import {
Checks, Checks,
@@ -152,14 +152,32 @@ export async function sendPassword(command: UpdateSessionCommand) {
// this is a fake error message to hide that the user does not even exist // this is a fake error message to hide that the user does not even exist
return { error: "Could not verify password" }; return { error: "Could not verify password" };
} else { } else {
loginSettings = await getLoginSettings({
serviceUrl,
organization: sessionCookie.organization,
});
if (!loginSettings) {
return { error: "Could not load login settings" };
}
let lifetime = loginSettings.passwordCheckLifetime;
if (!lifetime) {
console.warn("No password lifetime provided, defaulting to 24 hours");
lifetime = {
seconds: BigInt(60 * 60 * 24), // default to 24 hours
nanos: 0,
} as Duration;
}
try { try {
session = await setSessionAndUpdateCookie( session = await setSessionAndUpdateCookie({
sessionCookie, recentCookie: sessionCookie,
command.checks, checks: command.checks,
undefined, requestId: command.requestId,
command.requestId, lifetime,
loginSettings?.passwordCheckLifetime, });
);
} catch (error: any) { } catch (error: any) {
if ("failedAttempts" in error && error.failedAttempts) { if ("failedAttempts" in error && error.failedAttempts) {
const lockoutSettings = await getLockoutSettings({ const lockoutSettings = await getLockoutSettings({

View File

@@ -154,19 +154,27 @@ export async function updateSession(options: UpdateSessionCommand) {
organization, organization,
}); });
const lifetime = checks?.webAuthN let lifetime = checks?.webAuthN
? loginSettings?.multiFactorCheckLifetime // TODO different lifetime for webauthn u2f/passkey ? loginSettings?.multiFactorCheckLifetime // TODO different lifetime for webauthn u2f/passkey
: checks?.otpEmail || checks?.otpSms : checks?.otpEmail || checks?.otpSms
? loginSettings?.secondFactorCheckLifetime ? loginSettings?.secondFactorCheckLifetime
: undefined; : undefined;
const session = await setSessionAndUpdateCookie( if (!lifetime) {
recentSession, console.warn("No lifetime provided for session, defaulting to 24 hours");
lifetime = {
seconds: BigInt(60 * 60 * 24), // default to 24 hours
nanos: 0,
} as Duration;
}
const session = await setSessionAndUpdateCookie({
recentCookie: recentSession,
checks, checks,
challenges, challenges,
requestId, requestId,
lifetime, lifetime,
); });
if (!session) { if (!session) {
return { error: "Could not update session" }; return { error: "Could not update session" };

View File

@@ -298,7 +298,7 @@ export async function createSessionFromChecks({
}: { }: {
serviceUrl: string; serviceUrl: string;
checks: Checks; checks: Checks;
lifetime?: Duration; lifetime: Duration;
}) { }) {
const sessionService: Client<typeof SessionService> = const sessionService: Client<typeof SessionService> =
await createServiceForHost(SessionService, serviceUrl); await createServiceForHost(SessionService, serviceUrl);
@@ -320,7 +320,7 @@ export async function createSessionForUserIdAndIdpIntent({
idpIntentId?: string | undefined; idpIntentId?: string | undefined;
idpIntentToken?: string | undefined; idpIntentToken?: string | undefined;
}; };
lifetime?: Duration; lifetime: Duration;
}) { }) {
const sessionService: Client<typeof SessionService> = const sessionService: Client<typeof SessionService> =
await createServiceForHost(SessionService, serviceUrl); await createServiceForHost(SessionService, serviceUrl);
@@ -355,7 +355,7 @@ export async function setSession({
sessionToken: string; sessionToken: string;
challenges: RequestChallenges | undefined; challenges: RequestChallenges | undefined;
checks?: Checks; checks?: Checks;
lifetime?: Duration; lifetime: Duration;
}) { }) {
const sessionService: Client<typeof SessionService> = const sessionService: Client<typeof SessionService> =
await createServiceForHost(SessionService, serviceUrl); await createServiceForHost(SessionService, serviceUrl);

View File

@@ -8,6 +8,9 @@
"build:login:standalone": { "build:login:standalone": {
"outputs": ["dist/**", ".next/**", "!.next/cache/**"] "outputs": ["dist/**", ".next/**", "!.next/cache/**"]
}, },
"dev": {
"dependsOn": ["@zitadel/client#build", "@zitadel/proto#generate"]
},
"test": { "test": {
"dependsOn": ["@zitadel/client#build"] "dependsOn": ["@zitadel/client#build"]
}, },

201
pnpm-lock.yaml generated
View File

@@ -421,6 +421,9 @@ importers:
'@heroicons/react': '@heroicons/react':
specifier: 2.1.3 specifier: 2.1.3
version: 2.1.3(react@19.1.0) version: 2.1.3(react@19.1.0)
'@radix-ui/react-tooltip':
specifier: ^1.2.7
version: 1.2.7(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@tailwindcss/forms': '@tailwindcss/forms':
specifier: 0.5.7 specifier: 0.5.7
version: 0.5.7(tailwindcss@3.4.14) version: 0.5.7(tailwindcss@3.4.14)
@@ -4259,6 +4262,19 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true optional: true
'@radix-ui/react-tooltip@1.2.7':
resolution: {integrity: sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-use-callback-ref@1.1.0': '@radix-ui/react-use-callback-ref@1.1.0':
resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==}
peerDependencies: peerDependencies:
@@ -4398,6 +4414,19 @@ packages:
'@types/react-dom': '@types/react-dom':
optional: true optional: true
'@radix-ui/react-visually-hidden@1.2.3':
resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/rect@1.1.0': '@radix-ui/rect@1.1.0':
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
@@ -19496,6 +19525,15 @@ snapshots:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2) '@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-avatar@1.1.2(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-avatar@1.1.2(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/react-context': 1.1.1(@types/react@19.1.2)(react@18.3.1) '@radix-ui/react-context': 1.1.1(@types/react@19.1.2)(react@18.3.1)
@@ -19548,6 +19586,12 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.2)(react@19.1.0)':
dependencies:
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-context@1.1.1(@types/react@19.1.2)(react@18.3.1)': '@radix-ui/react-context@1.1.1(@types/react@19.1.2)(react@18.3.1)':
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
@@ -19560,6 +19604,12 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@radix-ui/react-context@1.1.2(@types/react@19.1.2)(react@19.1.0)':
dependencies:
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-direction@1.1.0(@types/react@19.1.2)(react@18.3.1)': '@radix-ui/react-direction@1.1.0(@types/react@19.1.2)(react@18.3.1)':
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
@@ -19585,6 +19635,19 @@ snapshots:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2) '@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-dismissable-layer@1.1.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-dismissable-layer@1.1.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/primitive': 1.1.1 '@radix-ui/primitive': 1.1.1
@@ -19676,6 +19739,13 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@radix-ui/react-id@1.1.1(@types/react@19.1.2)(react@19.1.0)':
dependencies:
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-popover@1.1.6(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-popover@1.1.6(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/primitive': 1.1.1 '@radix-ui/primitive': 1.1.1
@@ -19753,6 +19823,24 @@ snapshots:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2) '@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-popper@1.2.7(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@floating-ui/react-dom': 2.1.4(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-context': 1.1.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-use-size': 1.1.1(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/rect': 1.1.1
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-portal@1.1.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-portal@1.1.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -19783,6 +19871,16 @@ snapshots:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2) '@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-presence@1.1.2(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-presence@1.1.2(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.2)(react@18.3.1) '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.1.2)(react@18.3.1)
@@ -19803,6 +19901,16 @@ snapshots:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2) '@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-presence@1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-primitive@2.0.1(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-primitive@2.0.1(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/react-slot': 1.1.1(@types/react@19.1.2)(react@18.3.1) '@radix-ui/react-slot': 1.1.1(@types/react@19.1.2)(react@18.3.1)
@@ -19830,6 +19938,15 @@ snapshots:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2) '@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@radix-ui/react-slot': 1.2.3(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-roving-focus@1.1.10(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-roving-focus@1.1.10(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/primitive': 1.1.2 '@radix-ui/primitive': 1.1.2
@@ -19885,6 +20002,13 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@radix-ui/react-slot@1.2.3(@types/react@19.1.2)(react@19.1.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-tabs@1.1.12(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-tabs@1.1.12(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/primitive': 1.1.2 '@radix-ui/primitive': 1.1.2
@@ -19921,6 +20045,26 @@ snapshots:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2) '@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-tooltip@1.2.7(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@radix-ui/primitive': 1.1.2
'@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-context': 1.1.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-id': 1.1.1(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
'@radix-ui/react-slot': 1.2.3(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.1.2)(react@18.3.1)': '@radix-ui/react-use-callback-ref@1.1.0(@types/react@19.1.2)(react@18.3.1)':
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
@@ -19933,6 +20077,12 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.2)(react@19.1.0)':
dependencies:
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.1.2)(react@18.3.1)': '@radix-ui/react-use-controllable-state@1.1.0(@types/react@19.1.2)(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.2)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.2)(react@18.3.1)
@@ -19948,6 +20098,14 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.2)(react@19.1.0)':
dependencies:
'@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.2)(react@19.1.0)
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.2)(react@18.3.1)': '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.2)(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@18.3.1)
@@ -19955,6 +20113,13 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.2)(react@19.1.0)':
dependencies:
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.1.2)(react@18.3.1)': '@radix-ui/react-use-escape-keydown@1.1.0(@types/react@19.1.2)(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.2)(react@18.3.1) '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.2)(react@18.3.1)
@@ -19969,6 +20134,13 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.2)(react@19.1.0)':
dependencies:
'@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.1.2)(react@18.3.1)': '@radix-ui/react-use-layout-effect@1.1.0(@types/react@19.1.2)(react@18.3.1)':
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
@@ -19981,6 +20153,12 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.2)(react@19.1.0)':
dependencies:
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-use-previous@1.1.0(@types/react@19.1.2)(react@18.3.1)': '@radix-ui/react-use-previous@1.1.0(@types/react@19.1.2)(react@18.3.1)':
dependencies: dependencies:
react: 18.3.1 react: 18.3.1
@@ -20001,6 +20179,13 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@radix-ui/react-use-rect@1.1.1(@types/react@19.1.2)(react@19.1.0)':
dependencies:
'@radix-ui/rect': 1.1.1
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-use-size@1.1.0(@types/react@19.1.2)(react@18.3.1)': '@radix-ui/react-use-size@1.1.0(@types/react@19.1.2)(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.2)(react@18.3.1) '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.2)(react@18.3.1)
@@ -20015,6 +20200,13 @@ snapshots:
optionalDependencies: optionalDependencies:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@radix-ui/react-use-size@1.1.1(@types/react@19.1.2)(react@19.1.0)':
dependencies:
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@19.1.0)
react: 19.1.0
optionalDependencies:
'@types/react': 19.1.2
'@radix-ui/react-visually-hidden@1.1.1(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': '@radix-ui/react-visually-hidden@1.1.1(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
dependencies: dependencies:
'@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-primitive': 2.0.1(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@@ -20024,6 +20216,15 @@ snapshots:
'@types/react': 19.1.2 '@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2) '@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)':
dependencies:
'@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.2(@types/react@19.1.2))(@types/react@19.1.2)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react: 19.1.0
react-dom: 19.1.0(react@19.1.0)
optionalDependencies:
'@types/react': 19.1.2
'@types/react-dom': 19.1.2(@types/react@19.1.2)
'@radix-ui/rect@1.1.0': {} '@radix-ui/rect@1.1.0': {}
'@radix-ui/rect@1.1.1': {} '@radix-ui/rect@1.1.1': {}