mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 17:57:33 +00:00
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:
@@ -6,7 +6,9 @@
|
||||
"title": "Konten",
|
||||
"description": "Wählen Sie das Konto aus, das Sie verwenden möchten.",
|
||||
"addAnother": "Ein weiteres Konto hinzufügen",
|
||||
"noResults": "Keine Konten gefunden"
|
||||
"noResults": "Keine Konten gefunden",
|
||||
"verified": "verifiziert",
|
||||
"expired": "abgelaufen"
|
||||
},
|
||||
"logout": {
|
||||
"title": "Logout",
|
||||
|
@@ -6,7 +6,9 @@
|
||||
"title": "Accounts",
|
||||
"description": "Select the account you want to use.",
|
||||
"addAnother": "Add another account",
|
||||
"noResults": "No accounts found"
|
||||
"noResults": "No accounts found",
|
||||
"verified": "verified",
|
||||
"expired": "expired"
|
||||
},
|
||||
"logout": {
|
||||
"title": "Logout",
|
||||
|
@@ -4,9 +4,11 @@
|
||||
},
|
||||
"accounts": {
|
||||
"title": "Cuentas",
|
||||
"description": "Selecciona la cuenta que deseas usar.",
|
||||
"description": "Seleccione la cuenta que desea utilizar.",
|
||||
"addAnother": "Agregar otra cuenta",
|
||||
"noResults": "No se encontraron cuentas"
|
||||
"noResults": "No se encontraron cuentas",
|
||||
"verified": "verificado",
|
||||
"expired": "expirado"
|
||||
},
|
||||
"logout": {
|
||||
"title": "Cerrar sesión",
|
||||
|
@@ -4,9 +4,11 @@
|
||||
},
|
||||
"accounts": {
|
||||
"title": "Account",
|
||||
"description": "Seleziona l'account che desideri utilizzare.",
|
||||
"description": "Seleziona l'account che vuoi utilizzare.",
|
||||
"addAnother": "Aggiungi un altro account",
|
||||
"noResults": "Nessun account trovato"
|
||||
"noResults": "Nessun account trovato",
|
||||
"verified": "verificato",
|
||||
"expired": "scaduto"
|
||||
},
|
||||
"logout": {
|
||||
"title": "Esci",
|
||||
|
@@ -6,7 +6,9 @@
|
||||
"title": "Konta",
|
||||
"description": "Wybierz konto, którego chcesz użyć.",
|
||||
"addAnother": "Dodaj kolejne konto",
|
||||
"noResults": "Nie znaleziono kont"
|
||||
"noResults": "Nie znaleziono kont",
|
||||
"verified": "zweryfikowany",
|
||||
"expired": "wygasł"
|
||||
},
|
||||
"logout": {
|
||||
"title": "Wyloguj się",
|
||||
|
@@ -6,7 +6,9 @@
|
||||
"title": "Аккаунты",
|
||||
"description": "Выберите аккаунт, который хотите использовать.",
|
||||
"addAnother": "Добавить другой аккаунт",
|
||||
"noResults": "Аккаунты не найдены"
|
||||
"noResults": "Аккаунты не найдены",
|
||||
"verified": "проверенный",
|
||||
"expired": "истёк"
|
||||
},
|
||||
"logout": {
|
||||
"title": "Выход",
|
||||
|
@@ -4,9 +4,11 @@
|
||||
},
|
||||
"accounts": {
|
||||
"title": "账户",
|
||||
"description": "选择您想使用的账户。",
|
||||
"description": "选择您要使用的账户。",
|
||||
"addAnother": "添加另一个账户",
|
||||
"noResults": "未找到账户"
|
||||
"noResults": "未找到账户",
|
||||
"verified": "已验证",
|
||||
"expired": "已过期"
|
||||
},
|
||||
"logout": {
|
||||
"title": "注销",
|
||||
|
@@ -25,6 +25,7 @@
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^2.1.9",
|
||||
"@heroicons/react": "2.1.3",
|
||||
"@radix-ui/react-tooltip": "^1.2.7",
|
||||
"@tailwindcss/forms": "0.5.7",
|
||||
"@vercel/analytics": "^1.2.2",
|
||||
"@zitadel/client": "latest",
|
||||
|
@@ -15,12 +15,12 @@ import { headers } from "next/headers";
|
||||
import Link from "next/link";
|
||||
|
||||
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({
|
||||
serviceUrl,
|
||||
ids: ids.filter((id) => !!id) as string[],
|
||||
ids: cookieIds.filter((id) => !!id) as string[],
|
||||
});
|
||||
return response?.sessions ?? [];
|
||||
} else {
|
||||
|
@@ -5,6 +5,7 @@ import { LanguageSwitcher } from "@/components/language-switcher";
|
||||
import { Skeleton } from "@/components/skeleton";
|
||||
import { Theme } from "@/components/theme";
|
||||
import { ThemeProvider } from "@/components/theme-provider";
|
||||
import * as Tooltip from "@radix-ui/react-tooltip";
|
||||
import { Analytics } from "@vercel/analytics/react";
|
||||
import { Lato } from "next/font/google";
|
||||
import { ReactNode, Suspense } from "react";
|
||||
@@ -24,6 +25,7 @@ export default async function RootLayout({
|
||||
<head />
|
||||
<body>
|
||||
<ThemeProvider>
|
||||
<Tooltip.Provider>
|
||||
<Suspense
|
||||
fallback={
|
||||
<div
|
||||
@@ -54,6 +56,7 @@ export default async function RootLayout({
|
||||
</div>
|
||||
</LanguageProvider>
|
||||
</Suspense>
|
||||
</Tooltip.Provider>
|
||||
</ThemeProvider>
|
||||
<Analytics />
|
||||
</body>
|
||||
|
@@ -12,12 +12,12 @@ import { Organization } from "@zitadel/proto/zitadel/org/v2/org_pb";
|
||||
import { headers } from "next/headers";
|
||||
|
||||
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({
|
||||
serviceUrl,
|
||||
ids: ids.filter((id) => !!id) as string[],
|
||||
ids: cookieIds.filter((id) => !!id) as string[],
|
||||
});
|
||||
return response?.sessions ?? [];
|
||||
} else {
|
||||
|
@@ -41,17 +41,13 @@ export default async function Page(props: {
|
||||
const { method } = params;
|
||||
|
||||
const session = sessionId
|
||||
? await loadSessionById(serviceUrl, sessionId, organization)
|
||||
? await loadSessionById(sessionId, organization)
|
||||
: await loadMostRecentSession({
|
||||
serviceUrl,
|
||||
sessionParams: { loginName, organization },
|
||||
});
|
||||
|
||||
async function loadSessionById(
|
||||
host: string,
|
||||
sessionId: string,
|
||||
organization?: string,
|
||||
) {
|
||||
async function loadSessionById(sessionId: string, organization?: string) {
|
||||
const recent = await getSessionCookieById({ sessionId, organization });
|
||||
return getSession({
|
||||
serviceUrl,
|
||||
|
@@ -66,7 +66,6 @@ export default async function Page(props: {
|
||||
error = err;
|
||||
});
|
||||
} else if (method === "sms") {
|
||||
// does not work
|
||||
await addOTPSMS({
|
||||
serviceUrl,
|
||||
userId: session.factors.user.id,
|
||||
@@ -74,7 +73,6 @@ export default async function Page(props: {
|
||||
error = new Error("Could not add OTP via SMS");
|
||||
});
|
||||
} else if (method === "email") {
|
||||
// works
|
||||
await addOTPEmail({
|
||||
serviceUrl,
|
||||
userId: session.factors.user.id,
|
||||
@@ -106,6 +104,7 @@ export default async function Page(props: {
|
||||
paramsToContinue.append("requestId", requestId);
|
||||
}
|
||||
urlToContinue = `/otp/${method}?` + paramsToContinue;
|
||||
|
||||
// immediately check the OTP on the next page if sms or email was set up
|
||||
if (["email", "sms"].includes(method)) {
|
||||
return redirect(urlToContinue);
|
||||
|
@@ -3,6 +3,7 @@
|
||||
import { sendLoginname } from "@/lib/server/loginname";
|
||||
import { clearSession, continueWithSession } from "@/lib/server/session";
|
||||
import { XCircleIcon } from "@heroicons/react/24/outline";
|
||||
import * as Tooltip from "@radix-ui/react-tooltip";
|
||||
import { Timestamp, timestampDate } from "@zitadel/client";
|
||||
import { Session } from "@zitadel/proto/zitadel/session/v2/session_pb";
|
||||
import moment from "moment";
|
||||
@@ -10,6 +11,7 @@ import { useLocale } from "next-intl";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { Avatar } from "./avatar";
|
||||
import { Translated } from "./translated";
|
||||
|
||||
export function isSessionValid(session: Partial<Session>): {
|
||||
valid: boolean;
|
||||
@@ -66,6 +68,8 @@ export function SessionItem({
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<Tooltip.Root delayDuration={300}>
|
||||
<Tooltip.Trigger asChild>
|
||||
<button
|
||||
onClick={async () => {
|
||||
if (valid && session?.factors?.user) {
|
||||
@@ -119,12 +123,13 @@ export function SessionItem({
|
||||
</span>
|
||||
{valid ? (
|
||||
<span className="text-ellipsis text-xs opacity-80">
|
||||
<Translated i18nKey="verified" namespace="accounts" />{" "}
|
||||
{verifiedAt && moment(timestampDate(verifiedAt)).fromNow()}
|
||||
</span>
|
||||
) : (
|
||||
verifiedAt && (
|
||||
<span className="text-ellipsis text-xs opacity-80">
|
||||
expired{" "}
|
||||
<Translated i18nKey="expired" namespace="accounts" />{" "}
|
||||
{session.expirationDate &&
|
||||
moment(timestampDate(session.expirationDate)).fromNow()}
|
||||
</span>
|
||||
@@ -135,13 +140,13 @@ export function SessionItem({
|
||||
<span className="flex-grow"></span>
|
||||
<div className="relative flex flex-row items-center">
|
||||
{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
|
||||
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) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
@@ -152,5 +157,18 @@ export function SessionItem({
|
||||
/>
|
||||
</div>
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
@@ -242,7 +242,7 @@ export async function getSessionCookieByLoginName<T>({
|
||||
*/
|
||||
export async function getAllSessionCookieIds<T>(
|
||||
cleanup: boolean = false,
|
||||
): Promise<any> {
|
||||
): Promise<string[]> {
|
||||
const cookiesList = await cookies();
|
||||
const stringifiedCookie = cookiesList.get("sessions");
|
||||
|
||||
|
@@ -55,10 +55,21 @@ export async function createSessionAndUpdateCookie(command: {
|
||||
const _headers = await 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({
|
||||
serviceUrl,
|
||||
checks: command.checks,
|
||||
lifetime: command.lifetime,
|
||||
lifetime: sessionLifetime,
|
||||
});
|
||||
|
||||
if (createdSession) {
|
||||
@@ -126,11 +137,24 @@ export async function createSessionForIdpAndUpdateCookie({
|
||||
const _headers = await 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({
|
||||
serviceUrl,
|
||||
userId,
|
||||
idpIntent,
|
||||
lifetime,
|
||||
lifetime: sessionLifetime,
|
||||
}).catch((error: ErrorDetail | CredentialsCheckError) => {
|
||||
console.error("Could not set session", error);
|
||||
if ("failedAttempts" in error && error.failedAttempts) {
|
||||
@@ -190,41 +214,41 @@ export type SessionWithChallenges = Session & {
|
||||
challenges: Challenges | undefined;
|
||||
};
|
||||
|
||||
export async function setSessionAndUpdateCookie(
|
||||
recentCookie: CustomCookieData,
|
||||
checks?: Checks,
|
||||
challenges?: RequestChallenges,
|
||||
requestId?: string,
|
||||
lifetime?: Duration,
|
||||
) {
|
||||
export async function setSessionAndUpdateCookie(command: {
|
||||
recentCookie: CustomCookieData;
|
||||
checks?: Checks;
|
||||
challenges?: RequestChallenges;
|
||||
requestId?: string;
|
||||
lifetime: Duration;
|
||||
}) {
|
||||
const _headers = await headers();
|
||||
const { serviceUrl } = getServiceUrlFromHeaders(_headers);
|
||||
|
||||
return setSession({
|
||||
serviceUrl,
|
||||
sessionId: recentCookie.id,
|
||||
sessionToken: recentCookie.token,
|
||||
challenges,
|
||||
checks,
|
||||
lifetime,
|
||||
sessionId: command.recentCookie.id,
|
||||
sessionToken: command.recentCookie.token,
|
||||
challenges: command.challenges,
|
||||
checks: command.checks,
|
||||
lifetime: command.lifetime,
|
||||
})
|
||||
.then((updatedSession) => {
|
||||
if (updatedSession) {
|
||||
const sessionCookie: CustomCookieData = {
|
||||
id: recentCookie.id,
|
||||
id: command.recentCookie.id,
|
||||
token: updatedSession.sessionToken,
|
||||
creationTs: recentCookie.creationTs,
|
||||
expirationTs: recentCookie.expirationTs,
|
||||
creationTs: command.recentCookie.creationTs,
|
||||
expirationTs: command.recentCookie.expirationTs,
|
||||
// just overwrite the changeDate with the new one
|
||||
changeTs: updatedSession.details?.changeDate
|
||||
? `${timestampMs(updatedSession.details.changeDate)}`
|
||||
: "",
|
||||
loginName: recentCookie.loginName,
|
||||
organization: recentCookie.organization,
|
||||
loginName: command.recentCookie.loginName,
|
||||
organization: command.recentCookie.organization,
|
||||
};
|
||||
|
||||
if (requestId) {
|
||||
sessionCookie.requestId = requestId;
|
||||
if (command.requestId) {
|
||||
sessionCookie.requestId = command.requestId;
|
||||
}
|
||||
|
||||
return getSession({
|
||||
|
@@ -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,
|
||||
};
|
||||
});
|
||||
}
|
@@ -211,19 +211,27 @@ export async function sendPasskey(command: SendPasskeyCommand) {
|
||||
organization,
|
||||
});
|
||||
|
||||
const lifetime = checks?.webAuthN
|
||||
let lifetime = checks?.webAuthN
|
||||
? loginSettings?.multiFactorCheckLifetime // TODO different lifetime for webauthn u2f/passkey
|
||||
: checks?.otpEmail || checks?.otpSms
|
||||
? loginSettings?.secondFactorCheckLifetime
|
||||
: undefined;
|
||||
|
||||
const session = await setSessionAndUpdateCookie(
|
||||
recentSession,
|
||||
if (!lifetime) {
|
||||
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,
|
||||
undefined,
|
||||
requestId,
|
||||
lifetime,
|
||||
);
|
||||
});
|
||||
|
||||
if (!session || !session?.factors?.user?.id) {
|
||||
return { error: "Could not update session" };
|
||||
|
@@ -16,7 +16,7 @@ import {
|
||||
setPassword,
|
||||
setUserPassword,
|
||||
} from "@/lib/zitadel";
|
||||
import { ConnectError, create } from "@zitadel/client";
|
||||
import { ConnectError, create, Duration } from "@zitadel/client";
|
||||
import { createUserServiceClient } from "@zitadel/client/v2";
|
||||
import {
|
||||
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
|
||||
return { error: "Could not verify password" };
|
||||
} 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 {
|
||||
session = await setSessionAndUpdateCookie(
|
||||
sessionCookie,
|
||||
command.checks,
|
||||
undefined,
|
||||
command.requestId,
|
||||
loginSettings?.passwordCheckLifetime,
|
||||
);
|
||||
session = await setSessionAndUpdateCookie({
|
||||
recentCookie: sessionCookie,
|
||||
checks: command.checks,
|
||||
requestId: command.requestId,
|
||||
lifetime,
|
||||
});
|
||||
} catch (error: any) {
|
||||
if ("failedAttempts" in error && error.failedAttempts) {
|
||||
const lockoutSettings = await getLockoutSettings({
|
||||
|
@@ -154,19 +154,27 @@ export async function updateSession(options: UpdateSessionCommand) {
|
||||
organization,
|
||||
});
|
||||
|
||||
const lifetime = checks?.webAuthN
|
||||
let lifetime = checks?.webAuthN
|
||||
? loginSettings?.multiFactorCheckLifetime // TODO different lifetime for webauthn u2f/passkey
|
||||
: checks?.otpEmail || checks?.otpSms
|
||||
? loginSettings?.secondFactorCheckLifetime
|
||||
: undefined;
|
||||
|
||||
const session = await setSessionAndUpdateCookie(
|
||||
recentSession,
|
||||
if (!lifetime) {
|
||||
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,
|
||||
challenges,
|
||||
requestId,
|
||||
lifetime,
|
||||
);
|
||||
});
|
||||
|
||||
if (!session) {
|
||||
return { error: "Could not update session" };
|
||||
|
@@ -298,7 +298,7 @@ export async function createSessionFromChecks({
|
||||
}: {
|
||||
serviceUrl: string;
|
||||
checks: Checks;
|
||||
lifetime?: Duration;
|
||||
lifetime: Duration;
|
||||
}) {
|
||||
const sessionService: Client<typeof SessionService> =
|
||||
await createServiceForHost(SessionService, serviceUrl);
|
||||
@@ -320,7 +320,7 @@ export async function createSessionForUserIdAndIdpIntent({
|
||||
idpIntentId?: string | undefined;
|
||||
idpIntentToken?: string | undefined;
|
||||
};
|
||||
lifetime?: Duration;
|
||||
lifetime: Duration;
|
||||
}) {
|
||||
const sessionService: Client<typeof SessionService> =
|
||||
await createServiceForHost(SessionService, serviceUrl);
|
||||
@@ -355,7 +355,7 @@ export async function setSession({
|
||||
sessionToken: string;
|
||||
challenges: RequestChallenges | undefined;
|
||||
checks?: Checks;
|
||||
lifetime?: Duration;
|
||||
lifetime: Duration;
|
||||
}) {
|
||||
const sessionService: Client<typeof SessionService> =
|
||||
await createServiceForHost(SessionService, serviceUrl);
|
||||
|
@@ -8,6 +8,9 @@
|
||||
"build:login:standalone": {
|
||||
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
|
||||
},
|
||||
"dev": {
|
||||
"dependsOn": ["@zitadel/client#build", "@zitadel/proto#generate"]
|
||||
},
|
||||
"test": {
|
||||
"dependsOn": ["@zitadel/client#build"]
|
||||
},
|
||||
|
201
pnpm-lock.yaml
generated
201
pnpm-lock.yaml
generated
@@ -421,6 +421,9 @@ importers:
|
||||
'@heroicons/react':
|
||||
specifier: 2.1.3
|
||||
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':
|
||||
specifier: 0.5.7
|
||||
version: 0.5.7(tailwindcss@3.4.14)
|
||||
@@ -4259,6 +4262,19 @@ packages:
|
||||
'@types/react-dom':
|
||||
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':
|
||||
resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==}
|
||||
peerDependencies:
|
||||
@@ -4398,6 +4414,19 @@ packages:
|
||||
'@types/react-dom':
|
||||
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':
|
||||
resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==}
|
||||
|
||||
@@ -19496,6 +19525,15 @@ snapshots:
|
||||
'@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)':
|
||||
dependencies:
|
||||
'@radix-ui/react-context': 1.1.1(@types/react@19.1.2)(react@18.3.1)
|
||||
@@ -19548,6 +19586,12 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@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)':
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
@@ -19560,6 +19604,12 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@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)':
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
@@ -19585,6 +19635,19 @@ snapshots:
|
||||
'@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)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.1
|
||||
@@ -19676,6 +19739,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@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)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.1
|
||||
@@ -19753,6 +19823,24 @@ snapshots:
|
||||
'@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)':
|
||||
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)
|
||||
@@ -19783,6 +19871,16 @@ snapshots:
|
||||
'@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)':
|
||||
dependencies:
|
||||
'@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-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)':
|
||||
dependencies:
|
||||
'@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-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)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.2
|
||||
@@ -19885,6 +20002,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@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)':
|
||||
dependencies:
|
||||
'@radix-ui/primitive': 1.1.2
|
||||
@@ -19921,6 +20045,26 @@ snapshots:
|
||||
'@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)':
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
@@ -19933,6 +20077,12 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@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)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.2)(react@18.3.1)
|
||||
@@ -19948,6 +20098,14 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@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)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.2)(react@18.3.1)
|
||||
@@ -19955,6 +20113,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@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)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-callback-ref': 1.1.0(@types/react@19.1.2)(react@18.3.1)
|
||||
@@ -19969,6 +20134,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@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)':
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
@@ -19981,6 +20153,12 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@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)':
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
@@ -20001,6 +20179,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@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)':
|
||||
dependencies:
|
||||
'@radix-ui/react-use-layout-effect': 1.1.0(@types/react@19.1.2)(react@18.3.1)
|
||||
@@ -20015,6 +20200,13 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@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)':
|
||||
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)
|
||||
@@ -20024,6 +20216,15 @@ snapshots:
|
||||
'@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.1': {}
|
||||
|
Reference in New Issue
Block a user