diff --git a/cypress/e2e/i18n-nextjs/all.cy.ts b/cypress/e2e/i18n-nextjs/all.cy.ts index 26c93c0d0ade..e0175c8baeeb 100644 --- a/cypress/e2e/i18n-nextjs/all.cy.ts +++ b/cypress/e2e/i18n-nextjs/all.cy.ts @@ -6,6 +6,16 @@ Cypress.on("uncaught:exception", () => { }); describe("i18n-nextjs", () => { + const login = () => { + cy.fixture("demo-auth-credentials").then((auth) => { + cy.get("#email").clear(); + cy.get("#email").type(auth.email); + cy.get("#password").clear(); + cy.get("#password").type(auth.password); + }); + return cy.get("button[type=submit]").click(); + }; + beforeEach(() => { cy.clearAllCookies(); cy.clearAllLocalStorage(); @@ -16,6 +26,9 @@ describe("i18n-nextjs", () => { }); it("should change", () => { + login(); + cy.location("pathname").should("eq", "/blog-posts"); + cy.wait("@getBlogPosts"); // check the elements are in English which is the default language @@ -74,6 +87,9 @@ describe("i18n-nextjs", () => { }); it("should translate notifications", () => { + login(); + cy.location("pathname").should("eq", "/blog-posts"); + cy.visit("/blog-posts/edit/123"); cy.interceptGETBlogPost(); diff --git a/examples/i18n-nextjs/package.json b/examples/i18n-nextjs/package.json index eb90af2af31a..774301ad0603 100644 --- a/examples/i18n-nextjs/package.json +++ b/examples/i18n-nextjs/package.json @@ -20,6 +20,7 @@ "@refinedev/simple-rest": "^5.0.8", "antd": "^5.17.0", "cross-env": "^7.0.3", + "js-cookie": "^3.0.1", "next": "^14.1.0", "next-compose-plugins": "^2.2.1", "next-intl": "^3.25.3", diff --git a/examples/i18n-nextjs/public/locales/de/common.json b/examples/i18n-nextjs/public/locales/de/common.json index a8450d3bee41..6a2abdf8c850 100644 --- a/examples/i18n-nextjs/public/locales/de/common.json +++ b/examples/i18n-nextjs/public/locales/de/common.json @@ -5,35 +5,43 @@ "title": "Melden Sie sich bei Ihrem Konto an", "signin": "Einloggen", "signup": "Anmelden", + "register": "Registrieren", "divider": "oder", "fields": { "email": "Email", "password": "Passwort" }, "errors": { + "requiredEmail": "Email ist erforderlich", + "requiredPassword": "Passwort ist erforderlich", "validEmail": "Ungültige E-Mail-Adresse" }, "buttons": { "submit": "Anmeldung", "forgotPassword": "Passwort vergessen?", "noAccount": "Sie haben kein Konto?", + "haveAccount": "Haben Sie ein Konto?", "rememberMe": "Erinnere dich an mich" } }, "forgotPassword": { "title": "Haben Sie Ihr Passwort vergessen?", + "signin": "Einloggen", "fields": { "email": "Email" }, "errors": { + "requiredEmail": "Email ist erforderlich", "validEmail": "Ungültige E-Mail-Adresse" }, "buttons": { + "haveAccount": "Haben Sie ein Konto?", "submit": "Anweisungen zum Zurücksetzen senden" } }, "register": { "title": "Registrieren Sie sich für Ihr Konto", + "signin": "Einloggen", "fields": { "email": "Email", "password": "Passwort" @@ -70,7 +78,10 @@ "list": "Aufführen", "create": "Erstellen", "edit": "Bearbeiten", - "show": "Zeigen" + "show": "Zeigen", + "delete": "Löschen", + "save": "Speichern", + "cancel": "Abbrechen" }, "buttons": { "create": "Erstellen", @@ -111,28 +122,13 @@ }, "blog_posts": { "blog_posts": "Einträge", - "fields": { - "id": "Id", - "title": "Titel", - "category": "Kategorie", - "status": { - "title": "Status", - "published": "Veröffentlicht", - "draft": "Draft", - "rejected": "Abgelehnt" - }, - "content": "Inhalh", - "createdAt": "Erstellt am" + "form": { + "select": { + "category": { + "placeholder": "Bitte wählen Sie eine Kategorie" + } + } }, - "titles": { - "create": "Erstellen", - "edit": "Bearbeiten", - "list": "Einträge", - "show": "Eintrag zeigen" - } - }, - "posts": { - "posts": "Einträge", "fields": { "id": "Id", "title": "Titel", diff --git a/examples/i18n-nextjs/public/locales/en/common.json b/examples/i18n-nextjs/public/locales/en/common.json index 135d09f0774a..171fd477ad99 100644 --- a/examples/i18n-nextjs/public/locales/en/common.json +++ b/examples/i18n-nextjs/public/locales/en/common.json @@ -5,35 +5,43 @@ "title": "Sign in to your account", "signin": "Sign in", "signup": "Sign up", + "register": "Register", "divider": "or", "fields": { "email": "Email", "password": "Password" }, "errors": { + "requiredEmail": "Email is required", + "requiredPassword": "Password is required", "validEmail": "Invalid email address" }, "buttons": { "submit": "Login", "forgotPassword": "Forgot password?", "noAccount": "Don’t have an account?", + "haveAccount": "Have an account?", "rememberMe": "Remember me" } }, "forgotPassword": { "title": "Forgot your password?", + "signin": "Sign in", "fields": { "email": "Email" }, "errors": { + "requiredEmail": "Email is required", "validEmail": "Invalid email address" }, "buttons": { + "haveAccount": "Have an account?", "submit": "Send reset instructions" } }, "register": { "title": "Sign up for your account", + "signin": "Sign in", "fields": { "email": "Email", "password": "Password" @@ -70,7 +78,10 @@ "list": "List", "create": "Create", "edit": "Edit", - "show": "Show" + "show": "Show", + "delete": "Delete", + "save": "Save", + "cancel": "Cancel" }, "buttons": { "create": "Create", @@ -111,28 +122,13 @@ }, "blog_posts": { "blog_posts": "Blog Posts", - "fields": { - "id": "Id", - "title": "Title", - "category": "Category", - "status": { - "title": "Status", - "published": "Published", - "draft": "Draft", - "rejected": "Rejected" - }, - "content": "Content", - "createdAt": "Created At" + "form": { + "select": { + "category": { + "placeholder": "Please select category" + } + } }, - "titles": { - "create": "Create Post", - "edit": "Edit Post", - "list": "Posts", - "show": "Show Post" - } - }, - "posts": { - "posts": "Blog Posts", "fields": { "id": "Id", "title": "Title", diff --git a/examples/i18n-nextjs/src/app/_refine_context.tsx b/examples/i18n-nextjs/src/app/_refine_context.tsx index 9eea1e252b0f..e603cafcd298 100644 --- a/examples/i18n-nextjs/src/app/_refine_context.tsx +++ b/examples/i18n-nextjs/src/app/_refine_context.tsx @@ -8,6 +8,7 @@ import routerProvider from "@refinedev/nextjs-router"; import React, { Suspense, type PropsWithChildren } from "react"; import { ColorModeContextProvider } from "@contexts/color-mode"; import { dataProvider } from "@providers/data-provider"; +import { authProviderClient } from "@providers/auth-provider/auth-provider.client"; import { useLocale, useTranslations } from "next-intl"; import { setUserLocale } from "@i18n"; @@ -20,11 +21,10 @@ export const RefineContext = ({ children, }: PropsWithChildren) => { const t = useTranslations(); - const locale = useLocale(); const i18nProvider: I18nProvider = { translate: (key: string, options: any) => t(key, options), - getLocale: () => locale, + getLocale: useLocale, changeLocale: setUserLocale, }; @@ -38,6 +38,7 @@ export const RefineContext = ({ routerProvider={routerProvider} dataProvider={dataProvider} notificationProvider={useNotificationProvider} + authProvider={authProviderClient} i18nProvider={i18nProvider} resources={[ { diff --git a/examples/i18n-nextjs/src/app/blog-posts/create/page.tsx b/examples/i18n-nextjs/src/app/blog-posts/create/page.tsx index 14d0327be3d5..95ac83c18b46 100644 --- a/examples/i18n-nextjs/src/app/blog-posts/create/page.tsx +++ b/examples/i18n-nextjs/src/app/blog-posts/create/page.tsx @@ -1,10 +1,13 @@ "use client"; import { Create, useForm, useSelect } from "@refinedev/antd"; +import { useTranslation } from "@refinedev/core"; import { Form, Input, Select } from "antd"; export default function BlogPostCreate() { - const { formProps, saveButtonProps } = useForm({}); + const { translate: t } = useTranslation(); + + const { formProps, saveButtonProps } = useForm(); const { selectProps: categorySelectProps } = useSelect({ resource: "categories", @@ -14,7 +17,7 @@ export default function BlogPostCreate() {
- diff --git a/examples/i18n-nextjs/src/app/blog-posts/edit/[id]/page.tsx b/examples/i18n-nextjs/src/app/blog-posts/edit/[id]/page.tsx index 13a1a8d5f197..8435ee4646d9 100644 --- a/examples/i18n-nextjs/src/app/blog-posts/edit/[id]/page.tsx +++ b/examples/i18n-nextjs/src/app/blog-posts/edit/[id]/page.tsx @@ -6,7 +6,7 @@ import { Form, Input, Select } from "antd"; export default function BlogPostEdit() { const { translate: t } = useTranslation(); - const { formProps, saveButtonProps, query: queryResult } = useForm({}); + const { formProps, saveButtonProps, query: queryResult } = useForm(); const blogPostsData = queryResult?.data?.data; @@ -65,9 +65,15 @@ export default function BlogPostEdit() { - {errors?.password && ( - This field is required - )} - -
- - - {errors?.confirmPassword && ( - This field is required - )} -
- - - - ); + return { + authenticated, + redirectTo, + error, + }; } diff --git a/examples/with-nextjs-headless/src/components/auth-page/index.tsx b/examples/with-nextjs-headless/src/components/auth-page/index.tsx deleted file mode 100644 index 3cf8a6450ec6..000000000000 --- a/examples/with-nextjs-headless/src/components/auth-page/index.tsx +++ /dev/null @@ -1,16 +0,0 @@ -"use client"; - -import { AuthPage as AuthPageBase } from "@refinedev/core"; -import type { AuthPageProps } from "@refinedev/core"; - -export const AuthPage = (props: AuthPageProps) => { - return ( -
- -
-

Email: admin@refine.dev

-

Password: 123456

-
-
- ); -}; diff --git a/examples/with-nextjs-headless/src/providers/auth-provider/auth-provider.client.ts b/examples/with-nextjs-headless/src/providers/auth-provider/auth-provider.client.ts new file mode 100644 index 000000000000..66b0a7aa1311 --- /dev/null +++ b/examples/with-nextjs-headless/src/providers/auth-provider/auth-provider.client.ts @@ -0,0 +1,155 @@ +"use client"; + +import type { AuthProvider } from "@refinedev/core"; +import Cookies from "js-cookie"; + +const mockUsers = [ + { + email: "admin@refine.dev", + name: "John Doe", + avatar: "https://i.pravatar.cc/150?img=1", + roles: ["admin"], + }, + { + email: "editor@refine.dev", + name: "Jane Doe", + avatar: "https://i.pravatar.cc/150?img=1", + roles: ["editor"], + }, + { + email: "demo@refine.dev", + name: "Jane Doe", + avatar: "https://i.pravatar.cc/150?img=1", + roles: ["user"], + }, +]; + +export const authProviderClient: AuthProvider = { + login: async ({ email }) => { + // Suppose we actually send a request to the back end here. + const user = mockUsers.find((item) => item.email === email); + + if (user) { + Cookies.set("auth", JSON.stringify(user), { + expires: 30, // 30 days + path: "/", + }); + return { + success: true, + redirectTo: "/", + }; + } + + return { + success: false, + error: { + name: "LoginError", + message: "Invalid username or password", + }, + }; + }, + register: async (params) => { + // Suppose we actually send a request to the back end here. + const user = mockUsers.find((item) => item.email === params.email); + + if (user) { + Cookies.set("auth", JSON.stringify(user), { + expires: 30, // 30 days + path: "/", + }); + return { + success: true, + redirectTo: "/", + }; + } + return { + success: false, + error: { + message: "Register failed", + name: "Invalid email or password", + }, + }; + }, + forgotPassword: async (params) => { + // Suppose we actually send a request to the back end here. + const user = mockUsers.find((item) => item.email === params.email); + + if (user) { + //we can send email with reset password link here + return { + success: true, + }; + } + return { + success: false, + error: { + message: "Forgot password failed", + name: "Invalid email", + }, + }; + }, + updatePassword: async (params) => { + // Suppose we actually send a request to the back end here. + const isPasswordInvalid = params.password === "123456" || !params.password; + + if (isPasswordInvalid) { + return { + success: false, + error: { + message: "Update password failed", + name: "Invalid password", + }, + }; + } + + return { + success: true, + }; + }, + logout: async () => { + Cookies.remove("auth", { path: "/" }); + return { + success: true, + redirectTo: "/login", + }; + }, + check: async () => { + const auth = Cookies.get("auth"); + if (auth) { + return { + authenticated: true, + }; + } + + return { + authenticated: false, + logout: true, + redirectTo: "/login", + }; + }, + getPermissions: async () => { + const auth = Cookies.get("auth"); + if (auth) { + const parsedUser = JSON.parse(auth); + return parsedUser.roles; + } + return null; + }, + getIdentity: async () => { + const auth = Cookies.get("auth"); + if (auth) { + const parsedUser = JSON.parse(auth); + return parsedUser; + } + return null; + }, + onError: async (error) => { + if (error.response?.status === 401) { + return { + logout: true, + }; + } + + return { error }; + }, +}; diff --git a/examples/with-nextjs-headless/src/providers/auth-provider/auth-provider.server.ts b/examples/with-nextjs-headless/src/providers/auth-provider/auth-provider.server.ts index d722e535a383..1f9f97719d3b 100644 --- a/examples/with-nextjs-headless/src/providers/auth-provider/auth-provider.server.ts +++ b/examples/with-nextjs-headless/src/providers/auth-provider/auth-provider.server.ts @@ -1,5 +1,3 @@ -"use server"; - import type { AuthProvider } from "@refinedev/core"; import { cookies } from "next/headers"; diff --git a/examples/with-nextjs-headless/src/providers/auth-provider/index.ts b/examples/with-nextjs-headless/src/providers/auth-provider/index.ts deleted file mode 100644 index 6734cd53b868..000000000000 --- a/examples/with-nextjs-headless/src/providers/auth-provider/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./auth-provider"; -export * from "./auth-provider.server"; diff --git a/examples/with-nextjs/src/app/blog-posts/layout.tsx b/examples/with-nextjs/src/app/blog-posts/layout.tsx index 90ce9a6e4509..7db15132bf92 100644 --- a/examples/with-nextjs/src/app/blog-posts/layout.tsx +++ b/examples/with-nextjs/src/app/blog-posts/layout.tsx @@ -1,4 +1,4 @@ -import { authProviderServer } from "@providers/auth-provider"; +import { authProviderServer } from "@providers/auth-provider/auth-provider.server"; import { ThemedLayoutV2 } from "@refinedev/antd"; import { Header } from "@components/header"; import { redirect } from "next/navigation"; diff --git a/examples/with-nextjs/src/app/categories/layout.tsx b/examples/with-nextjs/src/app/categories/layout.tsx index 90ce9a6e4509..7db15132bf92 100644 --- a/examples/with-nextjs/src/app/categories/layout.tsx +++ b/examples/with-nextjs/src/app/categories/layout.tsx @@ -1,4 +1,4 @@ -import { authProviderServer } from "@providers/auth-provider"; +import { authProviderServer } from "@providers/auth-provider/auth-provider.server"; import { ThemedLayoutV2 } from "@refinedev/antd"; import { Header } from "@components/header"; import { redirect } from "next/navigation"; diff --git a/examples/with-nextjs/src/app/forgot-password/page.tsx b/examples/with-nextjs/src/app/forgot-password/page.tsx index 72d4dbc0fc63..4aae650d9f74 100644 --- a/examples/with-nextjs/src/app/forgot-password/page.tsx +++ b/examples/with-nextjs/src/app/forgot-password/page.tsx @@ -1,5 +1,5 @@ import { AuthPage } from "@components/auth-page"; -import { authProviderServer } from "@providers/auth-provider"; +import { authProviderServer } from "@providers/auth-provider/auth-provider.server"; import { redirect } from "next/navigation"; export default async function ForgotPassword() { diff --git a/examples/with-nextjs/src/app/layout.tsx b/examples/with-nextjs/src/app/layout.tsx index 3ecab51c1455..b8cc5ee73b02 100644 --- a/examples/with-nextjs/src/app/layout.tsx +++ b/examples/with-nextjs/src/app/layout.tsx @@ -8,7 +8,7 @@ import { cookies } from "next/headers"; import React, { Suspense } from "react"; import { ColorModeContextProvider } from "@contexts/color-mode"; -import { authProvider } from "@providers/auth-provider"; +import { authProviderClient } from "@providers/auth-provider/auth-provider.client"; import { dataProvider } from "@providers/data-provider"; import { AntdRegistry } from "@ant-design/nextjs-registry"; import "@refinedev/antd/dist/reset.css"; @@ -42,7 +42,7 @@ export default function RootLayout({ routerProvider={routerProvider} dataProvider={dataProvider} notificationProvider={useNotificationProvider} - authProvider={authProvider} + authProvider={authProviderClient} resources={[ { name: "blog_posts", diff --git a/examples/with-nextjs/src/app/login/page.tsx b/examples/with-nextjs/src/app/login/page.tsx index cfe99c572094..da90c7dd7a56 100644 --- a/examples/with-nextjs/src/app/login/page.tsx +++ b/examples/with-nextjs/src/app/login/page.tsx @@ -1,5 +1,5 @@ import { AuthPage } from "@components/auth-page"; -import { authProviderServer } from "@providers/auth-provider"; +import { authProviderServer } from "@providers/auth-provider/auth-provider.server"; import { redirect } from "next/navigation"; export default async function Login() { diff --git a/examples/with-nextjs/src/app/register/page.tsx b/examples/with-nextjs/src/app/register/page.tsx index bf26b7c12f92..62ecec410dd6 100644 --- a/examples/with-nextjs/src/app/register/page.tsx +++ b/examples/with-nextjs/src/app/register/page.tsx @@ -1,5 +1,5 @@ import { AuthPage } from "@components/auth-page"; -import { authProviderServer } from "@providers/auth-provider"; +import { authProviderServer } from "@providers/auth-provider/auth-provider.server"; import { redirect } from "next/navigation"; export default async function Register() { diff --git a/examples/with-nextjs/src/app/update-password/page.tsx b/examples/with-nextjs/src/app/update-password/page.tsx index 233dcc7259fa..94b83cd2440e 100644 --- a/examples/with-nextjs/src/app/update-password/page.tsx +++ b/examples/with-nextjs/src/app/update-password/page.tsx @@ -1,5 +1,5 @@ import { AuthPage } from "@components/auth-page"; -import { authProviderServer } from "@providers/auth-provider"; +import { authProviderServer } from "@providers/auth-provider/auth-provider.server"; import { redirect } from "next/navigation"; export default async function ForgotPassword() { diff --git a/examples/with-nextjs-headless/src/providers/auth-provider/auth-provider.ts b/examples/with-nextjs/src/providers/auth-provider/auth-provider.client.ts similarity index 98% rename from examples/with-nextjs-headless/src/providers/auth-provider/auth-provider.ts rename to examples/with-nextjs/src/providers/auth-provider/auth-provider.client.ts index 8a7226cb8356..40358f5afbe8 100644 --- a/examples/with-nextjs-headless/src/providers/auth-provider/auth-provider.ts +++ b/examples/with-nextjs/src/providers/auth-provider/auth-provider.client.ts @@ -24,7 +24,7 @@ const mockUsers = [ }, ]; -export const authProvider: AuthProvider = { +export const authProviderClient: AuthProvider = { login: async ({ email, username, password, remember }) => { // Suppose we actually send a request to the back end here. const user = mockUsers.find((item) => item.email === email); diff --git a/examples/with-nextjs/src/providers/auth-provider/index.ts b/examples/with-nextjs/src/providers/auth-provider/index.ts deleted file mode 100644 index 6734cd53b868..000000000000 --- a/examples/with-nextjs/src/providers/auth-provider/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./auth-provider"; -export * from "./auth-provider.server"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8ec0bd37f9a5..3a47e8146d6a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5023,6 +5023,9 @@ importers: cross-env: specifier: ^7.0.3 version: 7.0.3 + js-cookie: + specifier: ^3.0.1 + version: 3.0.5 next: specifier: ^14.1.0 version: 14.2.3(@babel/core@7.24.4)(babel-plugin-macros@3.1.0)(react-dom@18.3.0(react@18.3.0))(react@18.3.0)(sass@1.75.0) @@ -10911,7 +10914,7 @@ importers: devDependencies: '@esbuild-plugins/node-resolve': specifier: ^0.1.4 - version: 0.1.4(esbuild@0.17.19) + version: 0.1.4(esbuild@0.20.2) '@refinedev/core': specifier: ^4.52.0 version: link:../core @@ -10920,7 +10923,7 @@ importers: version: 29.5.12 jest: specifier: ^29.3.1 - version: 29.7.0(@types/node@18.19.31)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@18.19.31)(typescript@5.4.5)) + version: 29.7.0(@types/node@20.5.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.4.5)) jest-environment-jsdom: specifier: ^29.3.1 version: 29.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -10929,13 +10932,13 @@ importers: version: 13.5.4 ts-jest: specifier: ^29.1.2 - version: 29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.17.19)(jest@29.7.0(@types/node@18.19.31)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@18.19.31)(typescript@5.4.5)))(typescript@5.4.5) + version: 29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.20.2)(jest@29.7.0(@types/node@20.5.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.4.5)))(typescript@5.4.5) tslib: specifier: ^2.6.2 version: 2.6.2 tsup: specifier: ^6.7.0 - version: 6.7.0(postcss@8.4.38)(ts-node@10.9.2(@types/node@18.19.31)(typescript@5.4.5))(typescript@5.4.5) + version: 6.7.0(postcss@8.4.38)(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.4.5))(typescript@5.4.5) typescript: specifier: ^5.4.2 version: 5.4.5 @@ -10957,7 +10960,7 @@ importers: devDependencies: '@esbuild-plugins/node-resolve': specifier: ^0.1.4 - version: 0.1.4(esbuild@0.20.2) + version: 0.1.4(esbuild@0.17.19) '@refinedev/core': specifier: 4.56.0 version: link:../core @@ -10966,7 +10969,7 @@ importers: version: 29.5.12 jest: specifier: ^29.3.1 - version: 29.7.0(@types/node@20.5.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.4.5)) + version: 29.7.0(@types/node@18.19.31)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@18.19.31)(typescript@5.4.5)) jest-environment-jsdom: specifier: ^29.3.1 version: 29.7.0(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -10975,13 +10978,13 @@ importers: version: 13.5.4 ts-jest: specifier: ^29.1.2 - version: 29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.20.2)(jest@29.7.0(@types/node@20.5.1)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.4.5)))(typescript@5.4.5) + version: 29.1.2(@babel/core@7.24.4)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.24.4))(esbuild@0.17.19)(jest@29.7.0(@types/node@18.19.31)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@18.19.31)(typescript@5.4.5)))(typescript@5.4.5) tslib: specifier: ^2.6.2 version: 2.6.2 tsup: specifier: ^6.7.0 - version: 6.7.0(postcss@8.4.38)(ts-node@10.9.2(@types/node@20.5.1)(typescript@5.4.5))(typescript@5.4.5) + version: 6.7.0(postcss@8.4.38)(ts-node@10.9.2(@types/node@18.19.31)(typescript@5.4.5))(typescript@5.4.5) typescript: specifier: ^5.4.2 version: 5.4.5