From f18a592eab9897fcf5e256d3e13ee706d66cca48 Mon Sep 17 00:00:00 2001 From: Alexandre Anicio Date: Sun, 6 Oct 2024 12:56:31 -0300 Subject: [PATCH] updates --- .github/workflows/main.yml | 45 +- .github/workflows/release.yml | 61 +- .gitignore | 2 +- .../__mocks__/expo-secure-store.ts | 3 + .../useLogin/__tests__/useLogin.test.tsx | 2 +- .../__tests__/useSimpleTokenLogin.test.tsx | 3 +- .../modules/access/useLogin/index.ts | 65 +- .../modules/access/useLogin/types.ts | 7 +- .../useLogout/__tests__/useLogout.test.tsx | 39 +- .../modules/access/useLogout/index.ts | 16 +- .../modules/access/useLogout/types.ts | 4 +- .../modules/user/getUser/index.ts | 6 +- .../modules/user/getUser/types.ts | 6 +- .../getUserAsync/__tests__/fixtures/jwt.json | 3 + .../__tests__/getUserAsync.test.ts | 24 + .../modules/user/getUserAsync/index.ts | 24 + .../modules/user/getUserAsync/types.ts | 5 + packages/authentication/modules/user/index.ts | 2 +- .../useJWTUser/__tests__/useJWTUser.test.tsx | 3 +- .../modules/user/useJWTUser/index.ts | 9 +- .../modules/user/useJWTUser/types.ts | 4 +- .../__tests__/fixtures/request.json | 11 - .../__tests__/useSimpleTokenUser.test.tsx | 100 - .../modules/user/useSimpleTokenUser/index.ts | 41 - .../modules/user/useSimpleTokenUser/types.ts | 11 - .../__tests__/useUpdateUser.test.tsx | 3 +- .../modules/user/useUpdateUser/index.ts | 16 +- .../modules/user/useUpdateUser/types.ts | 4 +- .../modules/user/useUser/index.ts | 9 +- .../modules/user/useUser/types.ts | 4 +- packages/authentication/package.json | 2 +- packages/authentication/services/auth.ts | 16 - packages/authentication/services/mfa.ts | 5 +- packages/authentication/tsconfig.build.json | 4 + packages/authentication/tsconfig.json | 6 +- packages/authentication/types/auth.ts | 17 +- packages/authentication/utils/login.ts | 9 - packages/components/package.json | 2 +- packages/components/tsconfig.build.json | 4 + packages/components/tsconfig.json | 5 +- packages/config/.eslintrc.js | 1 + packages/config/.prettierrc.js | 4 + packages/config/package.json | 4 +- packages/design-system/package.json | 3 +- .../providers/ThemeProvider/index.tsx | 6 +- .../styles/material/next-emotion-cache.tsx | 97 - packages/design-system/tsconfig.build.json | 4 + packages/design-system/tsconfig.json | 5 +- packages/eslint-plugin/.eslintrc.js | 1 + packages/eslint-plugin/.prettierrc.js | 10 +- packages/eslint-plugin/tsconfig.json | 6 +- packages/graphql/package.json | 5 +- packages/graphql/tsconfig.build.json | 4 + packages/graphql/tsconfig.json | 5 +- packages/provider/package.json | 6 +- packages/provider/tsconfig.build.json | 4 + packages/provider/tsconfig.json | 5 +- packages/test/__mocks__/expo-secure-store.ts | 13 + packages/test/jest.config.ts | 5 +- packages/test/package.json | 5 +- packages/test/tsconfig.build.json | 4 + packages/test/tsconfig.json | 4 +- packages/tsconfig/lib.json | 2 +- packages/tsconfig/package.json | 1 - packages/utils/__mocks__/expo-secure-store.ts | 3 + packages/utils/constants/cookie.ts | 6 + packages/utils/constants/jwt.ts | 2 + packages/utils/constants/token.ts | 4 - .../__tests__/createAxiosInstance.test.ts | 9 +- .../axios/createAxiosInstance/index.ts | 25 +- packages/utils/functions/cookie/index.ts | 15 + .../__tests__/baseAppFetch.test.ts | 28 +- .../functions/fetch/baseAppFetch/index.ts | 28 +- .../functions/fetch/baseAppFetch/types.ts | 4 +- .../__tests__/getLanguage.client.test.ts | 6 +- .../__tests__/getLanguage.server.test.ts | 4 +- .../functions/language/getLanguage/index.ts | 4 +- .../functions/token/getAccessToken/index.ts | 21 +- .../__tests__/getToken.client.test.ts | 56 +- .../__tests__/getToken.server.test.ts | 30 +- .../utils/functions/token/getToken/index.ts | 12 +- .../__tests__/getTokenAsync.client.test.ts | 57 + .../__tests__/getTokenAsync.server.test.ts | 47 + .../functions/token/getTokenAsync/index.ts | 18 + packages/utils/functions/token/index.ts | 3 + .../__tests__/refreshAccessToken.test.ts | 29 +- .../token/refreshAccessToken/index.ts | 18 +- .../__tests__/removeTokenAsync.test.ts | 64 + .../functions/token/removeTokenAsync/index.ts | 15 + .../__tests__/setTokenAsync.test.ts | 79 + .../functions/token/setTokenAsync/index.ts | 16 + packages/utils/index.ts | 7 +- packages/utils/package.json | 3 +- packages/utils/tsconfig.build.json | 4 + packages/utils/tsconfig.json | 6 +- packages/utils/types/cookie.ts | 3 - packages/utils/types/jwt.ts | 4 + packages/utils/types/server.ts | 5 + pnpm-lock.yaml | 3750 ++++++++++++++--- 99 files changed, 3997 insertions(+), 1194 deletions(-) create mode 100644 packages/authentication/__mocks__/expo-secure-store.ts create mode 100644 packages/authentication/modules/user/getUserAsync/__tests__/fixtures/jwt.json create mode 100644 packages/authentication/modules/user/getUserAsync/__tests__/getUserAsync.test.ts create mode 100644 packages/authentication/modules/user/getUserAsync/index.ts create mode 100644 packages/authentication/modules/user/getUserAsync/types.ts delete mode 100644 packages/authentication/modules/user/useSimpleTokenUser/__tests__/fixtures/request.json delete mode 100644 packages/authentication/modules/user/useSimpleTokenUser/__tests__/useSimpleTokenUser.test.tsx delete mode 100644 packages/authentication/modules/user/useSimpleTokenUser/index.ts delete mode 100644 packages/authentication/modules/user/useSimpleTokenUser/types.ts create mode 100644 packages/authentication/tsconfig.build.json create mode 100644 packages/components/tsconfig.build.json delete mode 100644 packages/design-system/styles/material/next-emotion-cache.tsx create mode 100644 packages/design-system/tsconfig.build.json create mode 100644 packages/eslint-plugin/.eslintrc.js create mode 100644 packages/graphql/tsconfig.build.json create mode 100644 packages/provider/tsconfig.build.json create mode 100644 packages/test/__mocks__/expo-secure-store.ts create mode 100644 packages/test/tsconfig.build.json create mode 100644 packages/utils/__mocks__/expo-secure-store.ts create mode 100644 packages/utils/constants/jwt.ts delete mode 100644 packages/utils/constants/token.ts create mode 100644 packages/utils/functions/token/getTokenAsync/__tests__/getTokenAsync.client.test.ts create mode 100644 packages/utils/functions/token/getTokenAsync/__tests__/getTokenAsync.server.test.ts create mode 100644 packages/utils/functions/token/getTokenAsync/index.ts create mode 100644 packages/utils/functions/token/removeTokenAsync/__tests__/removeTokenAsync.test.ts create mode 100644 packages/utils/functions/token/removeTokenAsync/index.ts create mode 100644 packages/utils/functions/token/setTokenAsync/__tests__/setTokenAsync.test.ts create mode 100644 packages/utils/functions/token/setTokenAsync/index.ts create mode 100644 packages/utils/tsconfig.build.json delete mode 100644 packages/utils/types/cookie.ts diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 533a6b4d..65636b23 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -14,16 +14,20 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Setup Node.js 20.x - uses: actions/setup-node@v3 + - name: Setup Node.js 20.17.0 + uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 20.17.0 - - name: Install Dependencies - run: pnpm i + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.12.0 + - name: Install Dependencies + run: pnpm install --frozen-lockfile - name: Build Applications and Packages run: pnpm build @@ -32,33 +36,40 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node.js 20.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: - node-version: 20.x + node-version: 20.17.0 - - name: Install Dependencies - run: pnpm i + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.12.0 - - name: Lint Applications and Packages - run: pnpm lint + - name: Install Dependencies + run: pnpm install --frozen-lockfile test: name: Test runs-on: ubuntu-latest steps: - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node.js 20.x - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 + with: + node-version: 20.17.0 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 with: - node-version: 20.x + version: 9.12.0 - name: Install Dependencies - run: pnpm i + run: pnpm install --frozen-lockfile - name: Test Applications and Packages run: pnpm test diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 780a3c58..7478a86f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -9,26 +9,73 @@ on: concurrency: ${{ github.workflow }}-${{ github.ref }} jobs: + setup: + name: Setup and Install Dependencies + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Setup Node.js 20.17.0 + uses: actions/setup-node@v4 + with: + node-version: 20.17.0 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.12.0 + + - name: Restore pnpm Cache + uses: actions/cache/restore@v4 + with: + path: node_modules + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + + - name: Install Dependencies + run: pnpm install + env: + CI: true + + - name: Save pnpm Cache + uses: actions/cache/save@v4 + with: + path: node_modules + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + release: name: Release runs-on: ubuntu-latest + needs: setup steps: - name: Checkout Repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - - name: Setup Node.js 16.x - uses: actions/setup-node@v3 + - name: Setup Node.js 20.17.0 + uses: actions/setup-node@v4 with: - node-version: 18.x + node-version: 20.17.0 - - name: Install Dependencies - run: yarn + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.12.0 + + - name: Restore pnpm Cache + uses: actions/cache/restore@v4 + with: + path: node_modules + key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- - name: Create Release Pull Request or Publish to npm id: changesets uses: changesets/action@v1 with: - publish: yarn release + publish: pnpm release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 290a8a9c..8cc17211 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. -# custom +# build dist # dependencies diff --git a/packages/authentication/__mocks__/expo-secure-store.ts b/packages/authentication/__mocks__/expo-secure-store.ts new file mode 100644 index 00000000..79868d90 --- /dev/null +++ b/packages/authentication/__mocks__/expo-secure-store.ts @@ -0,0 +1,3 @@ +module.exports = require('@baseapp-frontend/test/__mocks__/expo-secure-store.ts') + +export {} diff --git a/packages/authentication/modules/access/useLogin/__tests__/useLogin.test.tsx b/packages/authentication/modules/access/useLogin/__tests__/useLogin.test.tsx index 669c6998..697a22f6 100644 --- a/packages/authentication/modules/access/useLogin/__tests__/useLogin.test.tsx +++ b/packages/authentication/modules/access/useLogin/__tests__/useLogin.test.tsx @@ -19,7 +19,7 @@ describe('useLogin', () => { axiosMock.onPost('/auth/login').reply(200, { token: 'fake token', }) - cookiesMock.set.mockImplementation((cookieName: string) => cookieName) + cookiesMock.set.mockImplementation((accessKeyName: string) => accessKeyName) const email = 'test@tsl.io' const password = '123456789' diff --git a/packages/authentication/modules/access/useLogin/__tests__/useSimpleTokenLogin.test.tsx b/packages/authentication/modules/access/useLogin/__tests__/useSimpleTokenLogin.test.tsx index db1909b2..95f76974 100644 --- a/packages/authentication/modules/access/useLogin/__tests__/useSimpleTokenLogin.test.tsx +++ b/packages/authentication/modules/access/useLogin/__tests__/useSimpleTokenLogin.test.tsx @@ -1,5 +1,5 @@ import { ComponentWithProviders, MockAdapter, renderHook } from '@baseapp-frontend/test' -import { TokenTypes, axios } from '@baseapp-frontend/utils' +import { axios } from '@baseapp-frontend/utils' import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' @@ -34,7 +34,6 @@ describe('useSimpleTokenLogin', () => { hasOnSuccessRan = true }, }, - tokenType: TokenTypes.simple, }), { wrapper: ComponentWithProviders, diff --git a/packages/authentication/modules/access/useLogin/index.ts b/packages/authentication/modules/access/useLogin/index.ts index 0da8fd99..03d8bd74 100644 --- a/packages/authentication/modules/access/useLogin/index.ts +++ b/packages/authentication/modules/access/useLogin/index.ts @@ -3,97 +3,58 @@ import { useState } from 'react' import { - ACCESS_COOKIE_NAME, - REFRESH_COOKIE_NAME, - TokenTypes, + ACCESS_KEY_NAME, + REFRESH_KEY_NAME, setFormApiErrors, + setTokenAsync, } from '@baseapp-frontend/utils' import { zodResolver } from '@hookform/resolvers/zod' -import { useMutation, useQueryClient } from '@tanstack/react-query' -import Cookies from 'js-cookie' +import { useMutation } from '@tanstack/react-query' import { useForm } from 'react-hook-form' import AuthApi from '../../../services/auth' import MfaApi from '../../../services/mfa' -import { USER_API_KEY } from '../../../services/user' import type { LoginChangeExpiredPasswordRedirectResponse, LoginJWTResponse, LoginMfaRequest, LoginRequest, - LoginSimpleTokenResponse, } from '../../../types/auth' import { - isJWTResponse, isLoginChangeExpiredPasswordRedirectResponse, isLoginMfaResponse, } from '../../../utils/login' import { CODE_VALIDATION_INITIAL_VALUES, CODE_VALIDATION_SCHEMA } from '../../mfa/constants' -import { useSimpleTokenUser } from '../../user' import { DEFAULT_INITIAL_VALUES, DEFAULT_VALIDATION_SCHEMA } from './constants' import type { UseLoginOptions } from './types' -const jwtSuccessHandler = ( - response: LoginJWTResponse, - cookieName: string, - refreshCookieName: string, -) => { - Cookies.set(cookieName, response.access, { - secure: process.env.NODE_ENV === 'production', - }) - Cookies.set(refreshCookieName, response.refresh, { - secure: process.env.NODE_ENV === 'production', - }) -} - -const simpleTokenSuccessHandler = ( - response: LoginSimpleTokenResponse, - cookieName: string, - onSuccess: () => void, -) => { - Cookies.set(cookieName, response.token, { - secure: process.env.NODE_ENV === 'production', - }) - - onSuccess() -} - const useLogin = ({ loginFormOptions = {}, loginOptions = {}, mfaOptions = {}, - tokenType = TokenTypes.jwt, - cookieName = ACCESS_COOKIE_NAME, - refreshCookieName = REFRESH_COOKIE_NAME, + accessKeyName = ACCESS_KEY_NAME, + refreshKeyName = REFRESH_KEY_NAME, ApiClass = AuthApi, enableFormApiErrors = true, }: UseLoginOptions = {}) => { - const queryClient = useQueryClient() const [mfaEphemeralToken, setMfaEphemeralToken] = useState(null) - const { refetch: refetchUser } = useSimpleTokenUser({ options: { enabled: false } }) /* * Handles login success with the auth token in response */ async function handleLoginSuccess( - response: - | LoginJWTResponse - | LoginSimpleTokenResponse - | LoginChangeExpiredPasswordRedirectResponse, + response: LoginJWTResponse | LoginChangeExpiredPasswordRedirectResponse, ) { if (isLoginChangeExpiredPasswordRedirectResponse(response)) { return } - if (isJWTResponse(tokenType, response)) { - jwtSuccessHandler(response, cookieName, refreshCookieName) - } else { - simpleTokenSuccessHandler(response, cookieName, () => { - // by invalidating the cache we force a reload of /v1/users/me and the state used by useUser hook - queryClient.invalidateQueries({ queryKey: USER_API_KEY.getUser() }) - refetchUser() - }) - } + await setTokenAsync(accessKeyName, response.access, { + secure: process.env.NODE_ENV === 'production', + }) + await setTokenAsync(refreshKeyName, response.refresh, { + secure: process.env.NODE_ENV === 'production', + }) } const form = useForm({ diff --git a/packages/authentication/modules/access/useLogin/types.ts b/packages/authentication/modules/access/useLogin/types.ts index 110b8a9e..0eaab8a1 100644 --- a/packages/authentication/modules/access/useLogin/types.ts +++ b/packages/authentication/modules/access/useLogin/types.ts @@ -1,11 +1,9 @@ -import { TokenTypes } from '@baseapp-frontend/utils' - import type { UseMutationOptions } from '@tanstack/react-query' import type { UseFormProps } from 'react-hook-form' import AuthApi from '../../../services/auth' import type { - CustomCookieNames, + CustomJWTKeyNames, LoginMfaRequest, LoginRequest, LoginResponse, @@ -13,11 +11,10 @@ import type { type ApiClass = Pick -export interface UseLoginOptions extends CustomCookieNames { +export interface UseLoginOptions extends CustomJWTKeyNames { loginFormOptions?: UseFormProps> loginOptions?: UseMutationOptions mfaOptions?: UseMutationOptions - tokenType?: TokenTypes ApiClass?: ApiClass enableFormApiErrors?: boolean } diff --git a/packages/authentication/modules/access/useLogout/__tests__/useLogout.test.tsx b/packages/authentication/modules/access/useLogout/__tests__/useLogout.test.tsx index 6b87f548..50c7c6f6 100644 --- a/packages/authentication/modules/access/useLogout/__tests__/useLogout.test.tsx +++ b/packages/authentication/modules/access/useLogout/__tests__/useLogout.test.tsx @@ -1,32 +1,40 @@ import { ComponentWithProviders, renderHook } from '@baseapp-frontend/test' -import { LOGOUT_EVENT, eventEmitter } from '@baseapp-frontend/utils' - -import Cookies from 'js-cookie' +import { + ACCESS_KEY_NAME, + LOGOUT_EVENT, + REFRESH_KEY_NAME, + eventEmitter, + removeTokenAsync, +} from '@baseapp-frontend/utils' import { MFA_API_KEY } from '../../../../services/mfa' import { USER_API_KEY } from '../../../../services/user' import useLogout from '../index' const mockResetQueries = jest.fn() -jest.mock('js-cookie') jest.mock('@tanstack/react-query', () => ({ ...jest.requireActual('@tanstack/react-query'), useQueryClient: () => ({ resetQueries: mockResetQueries, }), })) +jest.mock('@baseapp-frontend/utils', () => ({ + ...jest.requireActual('@baseapp-frontend/utils'), + removeTokenAsync: jest.fn(), +})) describe('useLogout hook', () => { afterEach(() => { jest.clearAllMocks() }) - test('should remove the cookie and invalidate queries', () => { + test('should remove tokens and invalidate queries', async () => { const { result } = renderHook(() => useLogout(), { wrapper: ComponentWithProviders }) - result.current.logout() + await result.current.logout() - expect(Cookies.remove).toHaveBeenCalled() + expect(removeTokenAsync).toHaveBeenCalledWith(ACCESS_KEY_NAME) + expect(removeTokenAsync).toHaveBeenCalledWith(REFRESH_KEY_NAME) expect(mockResetQueries).toHaveBeenCalledWith({ queryKey: USER_API_KEY.getUser() }) expect(mockResetQueries).toHaveBeenCalledWith({ queryKey: MFA_API_KEY.default }) }) @@ -37,19 +45,30 @@ describe('useLogout hook', () => { wrapper: ComponentWithProviders, }) - result.current.logout() + await result.current.logout() expect(mockOnLogout).toHaveBeenCalled() }) - it('should emit the logout event if the flag emitLogoutEvent is set to true', () => { + test('should emit the logout event if the flag emitLogoutEvent is set to true', async () => { const emitSpy = jest.spyOn(eventEmitter, 'emit') const { result } = renderHook(() => useLogout({ emitLogoutEvent: true }), { wrapper: ComponentWithProviders, }) - result.current.logout() + await result.current.logout() expect(emitSpy).toHaveBeenCalledWith(LOGOUT_EVENT) }) + + test('should not emit the logout event if emitLogoutEvent is set to false', async () => { + const emitSpy = jest.spyOn(eventEmitter, 'emit') + const { result } = renderHook(() => useLogout({ emitLogoutEvent: false }), { + wrapper: ComponentWithProviders, + }) + + await result.current.logout() + + expect(emitSpy).not.toHaveBeenCalled() + }) }) diff --git a/packages/authentication/modules/access/useLogout/index.ts b/packages/authentication/modules/access/useLogout/index.ts index 57c57b1c..6561a991 100644 --- a/packages/authentication/modules/access/useLogout/index.ts +++ b/packages/authentication/modules/access/useLogout/index.ts @@ -1,28 +1,28 @@ import { - ACCESS_COOKIE_NAME, + ACCESS_KEY_NAME, LOGOUT_EVENT, - REFRESH_COOKIE_NAME, + REFRESH_KEY_NAME, eventEmitter, + removeTokenAsync, } from '@baseapp-frontend/utils' import { useQueryClient } from '@tanstack/react-query' -import Cookies from 'js-cookie' import { MFA_API_KEY } from '../../../services/mfa' import { USER_API_KEY } from '../../../services/user' import type { UseLogoutOptions } from './types' const useLogout = ({ - cookieName = ACCESS_COOKIE_NAME, - refreshCookieName = REFRESH_COOKIE_NAME, + accessKeyName = ACCESS_KEY_NAME, + refreshKeyName = REFRESH_KEY_NAME, onLogout, emitLogoutEvent = true, }: UseLogoutOptions = {}) => { const queryClient = useQueryClient() - const logout = () => { - Cookies.remove(cookieName) - Cookies.remove(refreshCookieName) + const logout = async () => { + await removeTokenAsync(accessKeyName) + await removeTokenAsync(refreshKeyName) queryClient.resetQueries({ queryKey: USER_API_KEY.getUser() }) queryClient.resetQueries({ queryKey: MFA_API_KEY.default }) onLogout?.() diff --git a/packages/authentication/modules/access/useLogout/types.ts b/packages/authentication/modules/access/useLogout/types.ts index dbaab8d6..5871e358 100644 --- a/packages/authentication/modules/access/useLogout/types.ts +++ b/packages/authentication/modules/access/useLogout/types.ts @@ -1,6 +1,6 @@ -import type { CustomCookieNames } from '../../../types/auth' +import type { CustomJWTKeyNames } from '../../../types/auth' -export interface UseLogoutOptions extends CustomCookieNames { +export interface UseLogoutOptions extends CustomJWTKeyNames { onLogout?: () => void emitLogoutEvent?: boolean } diff --git a/packages/authentication/modules/user/getUser/index.ts b/packages/authentication/modules/user/getUser/index.ts index 0af3b8e2..b8ca63b9 100644 --- a/packages/authentication/modules/user/getUser/index.ts +++ b/packages/authentication/modules/user/getUser/index.ts @@ -1,4 +1,4 @@ -import { ACCESS_COOKIE_NAME } from '@baseapp-frontend/utils/constants/cookie' +import { ACCESS_KEY_NAME } from '@baseapp-frontend/utils/constants/jwt' import { decodeJWT, getToken } from '@baseapp-frontend/utils/functions/token' import type { JWTContent } from '@baseapp-frontend/utils/types/jwt' @@ -6,10 +6,10 @@ import type { User } from '../../../types/user' import type { GetUserOptions } from './types' const getUser = & JWTContent>({ - cookieName = ACCESS_COOKIE_NAME, + key = ACCESS_KEY_NAME, noSSR = false, }: GetUserOptions = {}) => { - const token = getToken(cookieName, { noSSR }) + const token = getToken(key, { noSSR }) if (token) { try { const user = decodeJWT(token) diff --git a/packages/authentication/modules/user/getUser/types.ts b/packages/authentication/modules/user/getUser/types.ts index d6b65b9a..75d8b93c 100644 --- a/packages/authentication/modules/user/getUser/types.ts +++ b/packages/authentication/modules/user/getUser/types.ts @@ -1,5 +1,5 @@ import type { ServerSideRenderingOption } from '@baseapp-frontend/utils' -import type { CustomCookieNames } from '../../../types/auth' - -export interface GetUserOptions extends CustomCookieNames, ServerSideRenderingOption {} +export interface GetUserOptions extends ServerSideRenderingOption { + key?: string +} diff --git a/packages/authentication/modules/user/getUserAsync/__tests__/fixtures/jwt.json b/packages/authentication/modules/user/getUserAsync/__tests__/fixtures/jwt.json new file mode 100644 index 00000000..02e1dba7 --- /dev/null +++ b/packages/authentication/modules/user/getUserAsync/__tests__/fixtures/jwt.json @@ -0,0 +1,3 @@ +{ + "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjk1MDc2NDgyLCJpYXQiOjE2OTUwNzYxODIsImp0aSI6ImVmMTFhYWE3OGMyODQ4YTBiOWJiYWYwMTU5MjY3MWY5IiwidXNlcl9pZCI6MSwiaWQiOjEsImVtYWlsIjoidXNlckBjb21wYW55LmNvbSIsImlzX2VtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmV3X2VtYWlsIjoiIiwiaXNfbmV3X2VtYWlsX2NvbmZpcm1lZCI6ZmFsc2UsInJlZmVycmFsX2NvZGUiOiIiLCJmaXJzdF9uYW1lIjoiSm9obiIsImxhc3RfbmFtZSI6IkRvZSJ9.QSy7NSAzk7w49kC9BxdZR-x0J8RLHS4ZYa5Jk0aUcSk" +} diff --git a/packages/authentication/modules/user/getUserAsync/__tests__/getUserAsync.test.ts b/packages/authentication/modules/user/getUserAsync/__tests__/getUserAsync.test.ts new file mode 100644 index 00000000..3ba12633 --- /dev/null +++ b/packages/authentication/modules/user/getUserAsync/__tests__/getUserAsync.test.ts @@ -0,0 +1,24 @@ +import type { CookiesGetByNameFn } from '@baseapp-frontend/test' + +import Cookies from 'js-cookie' + +import getUserAsync from '../index' +import jwt from './fixtures/jwt.json' + +describe('getUserAsync', () => { + it('should return the user from the JWT cookie', async () => { + ;(Cookies.get as CookiesGetByNameFn) = jest.fn(() => jwt.token) + const user = await getUserAsync() + + expect(user?.email).toBe('user@company.com') + expect(user?.firstName).toBe('John') + expect(user?.lastName).toBe('Doe') + }) + + it('should return null if the JWT cookie is not set', async () => { + ;(Cookies.get as CookiesGetByNameFn) = jest.fn(() => undefined) + const user = await getUserAsync() + + expect(user).toBeNull() + }) +}) diff --git a/packages/authentication/modules/user/getUserAsync/index.ts b/packages/authentication/modules/user/getUserAsync/index.ts new file mode 100644 index 00000000..7edc1611 --- /dev/null +++ b/packages/authentication/modules/user/getUserAsync/index.ts @@ -0,0 +1,24 @@ +import { ACCESS_KEY_NAME } from '@baseapp-frontend/utils/constants/jwt' +import { decodeJWT, getTokenAsync } from '@baseapp-frontend/utils/functions/token' +import type { JWTContent } from '@baseapp-frontend/utils/types/jwt' + +import type { User } from '../../../types/user' +import type { GetUserAsyncOptions } from './types' + +const getUserAsync = async & JWTContent>({ + key = ACCESS_KEY_NAME, + noSSR = false, +}: GetUserAsyncOptions = {}) => { + const token = await getTokenAsync(key, { noSSR }) + if (token) { + try { + const user = decodeJWT(token) + return user + } catch (error) { + return null + } + } + return null +} + +export default getUserAsync diff --git a/packages/authentication/modules/user/getUserAsync/types.ts b/packages/authentication/modules/user/getUserAsync/types.ts new file mode 100644 index 00000000..bdba6366 --- /dev/null +++ b/packages/authentication/modules/user/getUserAsync/types.ts @@ -0,0 +1,5 @@ +import type { ServerSideRenderingOption } from '@baseapp-frontend/utils' + +export interface GetUserAsyncOptions extends ServerSideRenderingOption { + key?: string +} diff --git a/packages/authentication/modules/user/index.ts b/packages/authentication/modules/user/index.ts index 12a402f5..e0e5313e 100644 --- a/packages/authentication/modules/user/index.ts +++ b/packages/authentication/modules/user/index.ts @@ -1,5 +1,5 @@ export { default as getUser } from './getUser' -export { default as useSimpleTokenUser } from './useSimpleTokenUser' +export { default as getUserAsync } from './getUserAsync' export { default as useUpdateUser } from './useUpdateUser' export { default as useJWTUser } from './useJWTUser' export { default as useUser } from './useUser' diff --git a/packages/authentication/modules/user/useJWTUser/__tests__/useJWTUser.test.tsx b/packages/authentication/modules/user/useJWTUser/__tests__/useJWTUser.test.tsx index cb32b989..90e6d038 100644 --- a/packages/authentication/modules/user/useJWTUser/__tests__/useJWTUser.test.tsx +++ b/packages/authentication/modules/user/useJWTUser/__tests__/useJWTUser.test.tsx @@ -5,7 +5,7 @@ import { renderHook, waitFor, } from '@baseapp-frontend/test' -import { TokenTypes, axios } from '@baseapp-frontend/utils' +import { axios } from '@baseapp-frontend/utils' import type { UseQueryResult } from '@tanstack/react-query' import Cookies from 'js-cookie' @@ -35,7 +35,6 @@ describe('useJWTUser', () => { })) beforeAll(async () => { - process.env.NEXT_PUBLIC_TOKEN_TYPE = TokenTypes.jwt useJWTUser = (await import('../index')).default as any // freeze time to jest.useFakeTimers().setSystemTime(new Date(2020, 9, 1, 7)) diff --git a/packages/authentication/modules/user/useJWTUser/index.ts b/packages/authentication/modules/user/useJWTUser/index.ts index 0c50f2a9..397b493d 100644 --- a/packages/authentication/modules/user/useJWTUser/index.ts +++ b/packages/authentication/modules/user/useJWTUser/index.ts @@ -1,10 +1,9 @@ import { useEffect } from 'react' -import { ACCESS_COOKIE_NAME } from '@baseapp-frontend/utils' +import { ACCESS_KEY_NAME, getToken } from '@baseapp-frontend/utils' import type { JWTContent } from '@baseapp-frontend/utils/types/jwt' import { useQuery, useQueryClient } from '@tanstack/react-query' -import Cookies from 'js-cookie' import UserApi, { USER_API_KEY } from '../../../services/user' import type { User } from '../../../types/user' @@ -20,14 +19,14 @@ import type { UseJWTUserOptions } from './types' */ const useJWTUser = & JWTContent>({ options, - cookieName = ACCESS_COOKIE_NAME, + accessKeyName = ACCESS_KEY_NAME, ApiClass = UserApi, noSSR = false, }: UseJWTUserOptions = {}) => { // TODO: placeholderData generic type is not working as expected, open an issue on react-query github type NonFunctionGuard = T extends Function ? never : T - const token = Cookies.get(cookieName) ?? '' - const placeholderData = getUser({ cookieName, noSSR }) as NonFunctionGuard + const token = getToken(accessKeyName, { noSSR }) ?? '' + const placeholderData = getUser({ key: accessKeyName, noSSR }) as NonFunctionGuard const queryClient = useQueryClient() diff --git a/packages/authentication/modules/user/useJWTUser/types.ts b/packages/authentication/modules/user/useJWTUser/types.ts index f9ae29ba..5de261aa 100644 --- a/packages/authentication/modules/user/useJWTUser/types.ts +++ b/packages/authentication/modules/user/useJWTUser/types.ts @@ -1,13 +1,13 @@ import type { ServerSideRenderingOption } from '@baseapp-frontend/utils' import UserApi from '../../../services/user' -import type { CustomCookieNames } from '../../../types/auth' +import type { CustomJWTKeyNames } from '../../../types/auth' import type { CustomUseQueryOptions } from '../../../types/react-query' type ApiClass = Pick export interface UseJWTUserOptions - extends CustomCookieNames, + extends CustomJWTKeyNames, ServerSideRenderingOption, CustomUseQueryOptions { ApiClass?: ApiClass diff --git a/packages/authentication/modules/user/useSimpleTokenUser/__tests__/fixtures/request.json b/packages/authentication/modules/user/useSimpleTokenUser/__tests__/fixtures/request.json deleted file mode 100644 index a9d79733..00000000 --- a/packages/authentication/modules/user/useSimpleTokenUser/__tests__/fixtures/request.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "email": "janedoe@example.com", - "id": 123, - "firstName": "Jane", - "lastName": "Doe", - "isEmailVerified": true, - "isNewEmailConfirmed": false, - "newEmail": "", - "referralCode": "1234", - "preferredLanguage": "en" -} diff --git a/packages/authentication/modules/user/useSimpleTokenUser/__tests__/useSimpleTokenUser.test.tsx b/packages/authentication/modules/user/useSimpleTokenUser/__tests__/useSimpleTokenUser.test.tsx deleted file mode 100644 index 3499f8d4..00000000 --- a/packages/authentication/modules/user/useSimpleTokenUser/__tests__/useSimpleTokenUser.test.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import { - ComponentWithProviders, - type CookiesGetByNameFn, - MockAdapter, - renderHook, - waitFor, -} from '@baseapp-frontend/test' - -import type { UseQueryResult } from '@tanstack/react-query' -import Cookies from 'js-cookie' - -import type { User } from '../../../../types/user' -import type { UseSimpleTokenUserOptions } from '../types' -import request from './fixtures/request.json' - -interface UseSimpleTokenUserOptionsResult - extends Omit, 'data'> { - user?: TUser -} - -describe('useSimpleTokenUser', () => { - let useSimpleTokenUser: >( - props?: UseSimpleTokenUserOptions, - ) => UseSimpleTokenUserOptionsResult - let defaultTokenType: string | undefined - let axios: any - let axiosMock: MockAdapter - - beforeAll(async () => { - defaultTokenType = process.env.NEXT_PUBLIC_TOKEN_TYPE - process.env.NEXT_PUBLIC_TOKEN_TYPE = 'simple' - axios = (await import('@baseapp-frontend/utils')).axios - axiosMock = new MockAdapter(axios) - useSimpleTokenUser = (await import('../index')).default as any - }) - - afterAll(() => { - process.env.NEXT_PUBLIC_TOKEN_TYPE = defaultTokenType - }) - - test('should user be present for authenticated', async () => { - ;(Cookies.get as CookiesGetByNameFn) = jest.fn(() => 'fake token') - - axiosMock.onGet('/users/me').reply(200, request) - - const { result } = renderHook(() => useSimpleTokenUser(), { - wrapper: ComponentWithProviders, - }) - - expect(result.current.isLoading).toBe(true) - await waitFor(() => expect(result.current.isSuccess).toBeTruthy()) - - expect(result.current.user?.email).toBe(request.email) - }) - - test('can use a custom type interface', async () => { - ;(Cookies.get as CookiesGetByNameFn) = jest.fn(() => 'fake token') - - interface CustomUser extends User { - customField: number - } - - axiosMock.onGet('/users/me').reply(200, { ...request, customField: 123 }) - - const { result } = renderHook(() => useSimpleTokenUser(), { - wrapper: ComponentWithProviders, - }) - expect(result.current.isLoading).toBe(true) - await waitFor(() => expect(result.current.isSuccess).toBeTruthy()) - - expect(result.current.user?.customField).toBe(123) - }) - - test('should remove cookie if 401', async () => { - ;(Cookies.get as CookiesGetByNameFn) = jest.fn(() => 'fake token') - ;(Cookies.remove as CookiesGetByNameFn) = jest.fn(() => '') - - axiosMock.onGet('/users/me').reply(401, { - error: 'Invalid token.', - }) - - const { result } = renderHook( - () => - useSimpleTokenUser({ - options: { - retry: false, - }, - }), - { - wrapper: ComponentWithProviders, - }, - ) - - await waitFor(() => expect(Cookies.get).toHaveBeenCalled()) - await waitFor(() => expect(Cookies.remove).toHaveBeenCalled()) - expect(result.current.user).not.toBeDefined() - }) - - process.env.NEXT_PUBLIC_TOKEN_TYPE = defaultTokenType -}) diff --git a/packages/authentication/modules/user/useSimpleTokenUser/index.ts b/packages/authentication/modules/user/useSimpleTokenUser/index.ts deleted file mode 100644 index 9552ab2d..00000000 --- a/packages/authentication/modules/user/useSimpleTokenUser/index.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { useEffect } from 'react' - -import { ACCESS_COOKIE_NAME } from '@baseapp-frontend/utils' - -import { useQuery, useQueryClient } from '@tanstack/react-query' -import Cookies from 'js-cookie' - -import UserApi, { USER_API_KEY } from '../../../services/user' -import type { User } from '../../../types/user' -import type { UseSimpleTokenUserOptions } from './types' - -const useSimpleTokenUser = >({ - options, - cookieName = ACCESS_COOKIE_NAME, - ApiClass = UserApi, -}: UseSimpleTokenUserOptions = {}) => { - const token = Cookies.get(cookieName) - const queryClient = useQueryClient() - - const { data: user, ...query } = useQuery({ - queryFn: () => ApiClass.getUser(), - queryKey: USER_API_KEY.getUser(), - staleTime: Infinity, // makes cache never expire automatically - enabled: !!token, - throwOnError: false, - ...options, // needs to be placed bellow all overridable options - }) - - useEffect(() => { - if ((query.error as any)?.response?.status === 401) { - Cookies.remove(cookieName) - - // making sure to reset the cache - queryClient.resetQueries({ queryKey: USER_API_KEY.getUser() }) - } - }, [query.error]) - - return { user, ...query } -} - -export default useSimpleTokenUser diff --git a/packages/authentication/modules/user/useSimpleTokenUser/types.ts b/packages/authentication/modules/user/useSimpleTokenUser/types.ts deleted file mode 100644 index 1d3b2806..00000000 --- a/packages/authentication/modules/user/useSimpleTokenUser/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -import UserApi from '../../../services/user' -import type { CustomCookieNames } from '../../../types/auth' -import type { CustomUseQueryOptions } from '../../../types/react-query' - -type ApiClass = Pick - -export interface UseSimpleTokenUserOptions - extends CustomCookieNames, - CustomUseQueryOptions { - ApiClass?: ApiClass -} diff --git a/packages/authentication/modules/user/useUpdateUser/__tests__/useUpdateUser.test.tsx b/packages/authentication/modules/user/useUpdateUser/__tests__/useUpdateUser.test.tsx index 44588d27..feef7973 100644 --- a/packages/authentication/modules/user/useUpdateUser/__tests__/useUpdateUser.test.tsx +++ b/packages/authentication/modules/user/useUpdateUser/__tests__/useUpdateUser.test.tsx @@ -5,7 +5,7 @@ import { renderHook, waitFor, } from '@baseapp-frontend/test' -import { TokenTypes, axios } from '@baseapp-frontend/utils' +import { axios } from '@baseapp-frontend/utils' import type { UseMutationResult } from '@tanstack/react-query' import Cookies from 'js-cookie' @@ -42,7 +42,6 @@ describe('useUserUpdate', () => { })) beforeAll(async () => { - process.env.NEXT_PUBLIC_TOKEN_TYPE = TokenTypes.jwt useUserUpdate = (await import('../index')).default as any // freeze time to jest.useFakeTimers().setSystemTime(new Date(2020, 9, 1, 7)) diff --git a/packages/authentication/modules/user/useUpdateUser/index.ts b/packages/authentication/modules/user/useUpdateUser/index.ts index cda54333..31362f56 100644 --- a/packages/authentication/modules/user/useUpdateUser/index.ts +++ b/packages/authentication/modules/user/useUpdateUser/index.ts @@ -1,9 +1,4 @@ -import { - ACCESS_COOKIE_NAME, - REFRESH_COOKIE_NAME, - TokenTypes, - refreshAccessToken, -} from '@baseapp-frontend/utils' +import { ACCESS_KEY_NAME, REFRESH_KEY_NAME, refreshAccessToken } from '@baseapp-frontend/utils' import { useMutation, useQueryClient } from '@tanstack/react-query' @@ -13,8 +8,8 @@ import type { UseUpdateUserOptions } from './types' const useUpdateUser = >({ options, - cookieName = ACCESS_COOKIE_NAME, - refreshCookieName = REFRESH_COOKIE_NAME, + accessKeyName = ACCESS_KEY_NAME, + refreshKeyName = REFRESH_KEY_NAME, ApiClass = UserApi, }: UseUpdateUserOptions = {}) => { const queryClient = useQueryClient() @@ -24,10 +19,7 @@ const useUpdateUser = >({ onSettled: async (data, error, variables, context) => { queryClient.invalidateQueries({ queryKey: USER_API_KEY.getUser() }) try { - const tokenType = process.env.NEXT_PUBLIC_TOKEN_TYPE as TokenTypes - if (tokenType === TokenTypes.jwt) { - await refreshAccessToken(cookieName, refreshCookieName) - } + await refreshAccessToken(accessKeyName, refreshKeyName) } catch (e) { // silently fail // eslint-disable-next-line no-console diff --git a/packages/authentication/modules/user/useUpdateUser/types.ts b/packages/authentication/modules/user/useUpdateUser/types.ts index e442edf0..a2160c27 100644 --- a/packages/authentication/modules/user/useUpdateUser/types.ts +++ b/packages/authentication/modules/user/useUpdateUser/types.ts @@ -1,12 +1,12 @@ import type { UseMutationOptions } from '@tanstack/react-query' import UserApi from '../../../services/user' -import type { CustomCookieNames } from '../../../types/auth' +import type { CustomJWTKeyNames } from '../../../types/auth' import type { User, UserUpdateParams } from '../../../types/user' type ApiClass = Pick -export interface UseUpdateUserOptions> extends CustomCookieNames { +export interface UseUpdateUserOptions> extends CustomJWTKeyNames { options?: UseMutationOptions, { previousUser?: TUser }> ApiClass?: ApiClass } diff --git a/packages/authentication/modules/user/useUser/index.ts b/packages/authentication/modules/user/useUser/index.ts index ef88608a..5cbe185d 100644 --- a/packages/authentication/modules/user/useUser/index.ts +++ b/packages/authentication/modules/user/useUser/index.ts @@ -1,4 +1,4 @@ -import { ACCESS_COOKIE_NAME, decodeJWT } from '@baseapp-frontend/utils' +import { ACCESS_KEY_NAME, decodeJWT } from '@baseapp-frontend/utils' import type { JWTContent } from '@baseapp-frontend/utils/types/jwt' import Cookies from 'js-cookie' @@ -12,13 +12,12 @@ import type { UseUserOptions } from './types' * - Prefer using the `getUser` function. * * On the client side: - * - If you are using `JWT`, prefer using the `useJWTUser` hook. - * - If you are using `Simple Token`, prefer using the `useSimpleTokenUser` hook. + * - Prefer using the `useJWTUser` hook. */ const useUser = & Partial>({ - cookieName = ACCESS_COOKIE_NAME, + accessKeyName = ACCESS_KEY_NAME, }: UseUserOptions = {}): TUser | null => { - const token = Cookies.get(cookieName) + const token = Cookies.get(accessKeyName) if (token) { try { return decodeJWT(token) as TUser diff --git a/packages/authentication/modules/user/useUser/types.ts b/packages/authentication/modules/user/useUser/types.ts index cd5f8a89..6eee2866 100644 --- a/packages/authentication/modules/user/useUser/types.ts +++ b/packages/authentication/modules/user/useUser/types.ts @@ -1,3 +1,3 @@ -import type { CustomCookieNames } from '../../../types/auth' +import type { CustomJWTKeyNames } from '../../../types/auth' -export interface UseUserOptions extends CustomCookieNames {} +export interface UseUserOptions extends CustomJWTKeyNames {} diff --git a/packages/authentication/package.json b/packages/authentication/package.json index d3ab35b2..08b8cece 100644 --- a/packages/authentication/package.json +++ b/packages/authentication/package.json @@ -6,7 +6,7 @@ "types": "dist/index.d.ts", "sideEffects": false, "scripts": { - "build": "rm -rf dist && tsc --build", + "build": "rm -rf dist && tsc --build tsconfig.build.json", "dev": "tsc --watch", "test": "jest --config ./jest.config.ts", "lint": "eslint . --ext .tsx --ext .ts && tsc --noEmit", diff --git a/packages/authentication/services/auth.ts b/packages/authentication/services/auth.ts index 1d7a0a58..5ef5c9dc 100644 --- a/packages/authentication/services/auth.ts +++ b/packages/authentication/services/auth.ts @@ -1,13 +1,10 @@ import { axios } from '@baseapp-frontend/utils' -import { TokenTypes } from '@baseapp-frontend/utils/constants/token' import type { ChangeExpiredPasswordRequest, ForgotPasswordRequest, LoginRequest, LoginResponse, - PreAuthRequest, - PreAuthResponse, RegisterRequest, ResetPasswordRequest, } from '../types/auth' @@ -29,17 +26,6 @@ export default class AuthApi { return axios.post(`/register`, request) } - static preAuth(request: PreAuthRequest, tokenType: TokenTypes): Promise { - switch (tokenType) { - case TokenTypes.jwt: - return axios.post(`/auth/pre-auth/jwt`, request) - case TokenTypes.simple: - return axios.post(`/auth/pre-auth/auth-token`, request) - default: - return Promise.reject(new Error(`Unknown token type: ${tokenType}`)) - } - } - static changeExpiredPassword({ currentPassword, newPassword, @@ -51,6 +37,4 @@ export default class AuthApi { export const AUTH_API_KEY = { default: ['auth'], - preAuth: (token: string, tokenType: TokenTypes) => - [...AUTH_API_KEY.default, 'preAuth', token, tokenType] as const, } diff --git a/packages/authentication/services/mfa.ts b/packages/authentication/services/mfa.ts index 45b9385e..eccd55a5 100644 --- a/packages/authentication/services/mfa.ts +++ b/packages/authentication/services/mfa.ts @@ -1,6 +1,6 @@ import { type DjangoPaginatedResponse, axios } from '@baseapp-frontend/utils' -import type { LoginMfaRequest, LoginSimpleTokenResponse } from '../types/auth' +import type { LoginMfaRequest } from '../types/auth' import type { MfaActivationResponse, MfaActiveMethodResponse, @@ -41,7 +41,8 @@ export default class MfaApi { return axios.post(`${baseUrl}/${method}/codes/regenerate/`, { code }) } - static loginStep2(data: LoginMfaRequest): Promise { + // TODO: review this endpoint + static loginStep2(data: LoginMfaRequest): Promise { return axios.post('/auth/login/code', data) } } diff --git a/packages/authentication/tsconfig.build.json b/packages/authentication/tsconfig.build.json new file mode 100644 index 00000000..deebe74b --- /dev/null +++ b/packages/authentication/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx", "**/*.cy.tsx"] +} diff --git a/packages/authentication/tsconfig.json b/packages/authentication/tsconfig.json index 4503a327..0a2b5f1e 100644 --- a/packages/authentication/tsconfig.json +++ b/packages/authentication/tsconfig.json @@ -1,8 +1,8 @@ { "extends": "@baseapp-frontend/tsconfig/lib.json", "compilerOptions": { - "outDir": "./dist", - "baseUrl": "." + "types": ["node", "jest"], + "outDir": "./dist" }, "include": [ "**/*.ts", @@ -15,5 +15,5 @@ "*.d.ts", "jest.config.ts" ], - "exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx"] + "exclude": ["node_modules"] } diff --git a/packages/authentication/types/auth.ts b/packages/authentication/types/auth.ts index 8096e01d..a64ac1bd 100644 --- a/packages/authentication/types/auth.ts +++ b/packages/authentication/types/auth.ts @@ -15,10 +15,6 @@ export interface LoginMfaResponse { method: MfaMethod } -export interface LoginSimpleTokenResponse { - token: string -} - export interface LoginJWTResponse { access: string refresh: string @@ -30,7 +26,6 @@ export interface LoginChangeExpiredPasswordRedirectResponse { export type LoginResponse = | LoginMfaResponse - | LoginSimpleTokenResponse | LoginJWTResponse | LoginChangeExpiredPasswordRedirectResponse @@ -49,17 +44,11 @@ export interface RegisterRequest { password: string } -export interface CustomCookieNames { - cookieName?: string - refreshCookieName?: string +export interface CustomJWTKeyNames { + accessKeyName?: string + refreshKeyName?: string } -export interface PreAuthRequest { - token: string -} - -export type PreAuthResponse = LoginSimpleTokenResponse | LoginJWTResponse - export interface ChangeExpiredPasswordRequest { currentPassword: string newPassword: string diff --git a/packages/authentication/utils/login.ts b/packages/authentication/utils/login.ts index a9b20e06..cc70c9c1 100644 --- a/packages/authentication/utils/login.ts +++ b/packages/authentication/utils/login.ts @@ -1,11 +1,7 @@ -import { TokenTypes } from '@baseapp-frontend/utils' - import type { LoginChangeExpiredPasswordRedirectResponse, - LoginJWTResponse, LoginMfaResponse, LoginResponse, - LoginSimpleTokenResponse, } from '../types/auth' export const isLoginMfaResponse = (data: LoginResponse): data is LoginMfaResponse => { @@ -13,11 +9,6 @@ export const isLoginMfaResponse = (data: LoginResponse): data is LoginMfaRespons return mfaKey in data } -export const isJWTResponse = ( - token: TokenTypes, - response?: LoginJWTResponse | LoginSimpleTokenResponse, -): response is LoginJWTResponse => token === TokenTypes.jwt - export const isLoginChangeExpiredPasswordRedirectResponse = ( data: LoginResponse, ): data is LoginChangeExpiredPasswordRedirectResponse => { diff --git a/packages/components/package.json b/packages/components/package.json index 25786126..a9fc03e3 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -6,7 +6,7 @@ "types": "dist/index.d.ts", "sideEffects": false, "scripts": { - "build": "rm -rf dist && tsc --build", + "build": "rm -rf dist && tsc --build tsconfig.build.json", "dev": "tsc --watch", "relay": "relay-compiler", "relay-download-schema": "dotenv -- bash -c 'get-graphql-schema \"$NEXT_PUBLIC_RELAY_ENDPOINT\" > schema.graphql'", diff --git a/packages/components/tsconfig.build.json b/packages/components/tsconfig.build.json new file mode 100644 index 00000000..deebe74b --- /dev/null +++ b/packages/components/tsconfig.build.json @@ -0,0 +1,4 @@ +{ + "extends": "./tsconfig.json", + "exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx", "**/*.cy.tsx"] +} diff --git a/packages/components/tsconfig.json b/packages/components/tsconfig.json index ba211366..26dc0e53 100644 --- a/packages/components/tsconfig.json +++ b/packages/components/tsconfig.json @@ -1,7 +1,8 @@ { "extends": "@baseapp-frontend/tsconfig/lib.json", "compilerOptions": { - "types": ["cypress", "@testing-library/cypress", "cypress-plugin-steps", "node", "jest"] + "types": ["cypress", "@testing-library/cypress", "cypress-plugin-steps", "node", "jest"], + "outDir": "./dist" }, "include": [ "**/*.ts", @@ -12,5 +13,5 @@ "*.tsx", "babel.config.js" ], - "exclude": ["node_modules", "**/*.test.ts", "**/*.test.tsx"] + "exclude": ["node_modules"] } diff --git a/packages/config/.eslintrc.js b/packages/config/.eslintrc.js index 91b1c492..f2db3d93 100644 --- a/packages/config/.eslintrc.js +++ b/packages/config/.eslintrc.js @@ -41,6 +41,7 @@ module.exports = { rules: { 'global-require': 0, '@emotion/jsx-import': 'error', + 'no-html-link-for-pages': 0, '@emotion/no-vanilla': 'error', '@emotion/import-from-emotion': 'error', '@emotion/styled-import': 'error', diff --git a/packages/config/.prettierrc.js b/packages/config/.prettierrc.js index 3fe7dc1d..9c90b25e 100644 --- a/packages/config/.prettierrc.js +++ b/packages/config/.prettierrc.js @@ -6,4 +6,8 @@ module.exports = { importOrder: ['^react$', '^@baseapp-frontend/(.*)$', '', '^[./]'], importOrderSeparation: true, importOrderSortSpecifiers: true, + plugins: [ + require.resolve('@trivago/prettier-plugin-sort-imports'), + require.resolve('prettier-plugin-tailwindcss'), // must be loaded last + ], } diff --git a/packages/config/package.json b/packages/config/package.json index 2b8cbed1..7c1b6347 100644 --- a/packages/config/package.json +++ b/packages/config/package.json @@ -2,7 +2,6 @@ "name": "@baseapp-frontend/config", "description": "Reusable configurations for eslint, prettier, jest and relay", "version": "2.1.8", - "main": "index.js", "files": [ ".eslintrc.js", "jest.config.js", @@ -25,7 +24,8 @@ "eslint-plugin-jsx-a11y": "catalog:lint", "eslint-plugin-react": "catalog:lint", "eslint-plugin-react-hooks": "catalog:lint", - "prettier": "catalog:lint" + "prettier": "catalog:lint", + "prettier-plugin-tailwindcss": "catalog:lint" }, "license": "MIT", "repository": { diff --git a/packages/design-system/package.json b/packages/design-system/package.json index fc56fc78..d42829a3 100644 --- a/packages/design-system/package.json +++ b/packages/design-system/package.json @@ -6,7 +6,7 @@ "types": "dist/index.d.ts", "sideEffects": false, "scripts": { - "build": "rm -rf dist && tsc --build", + "build": "rm -rf dist && tsc --build tsconfig.build.json", "dev": "tsc --watch", "lint": "eslint . --ext .tsx --ext .ts && tsc --noEmit", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", @@ -21,6 +21,7 @@ "@mui/icons-material": "catalog:material-ui", "@mui/lab": "catalog:material-ui", "@mui/material": "catalog:material-ui", + "@mui/material-nextjs": "^6.1.2", "@mui/x-date-pickers": "catalog:material-ui", "@storybook/react": "catalog:storybook", "framer-motion": "^11.2.10", diff --git a/packages/design-system/providers/ThemeProvider/index.tsx b/packages/design-system/providers/ThemeProvider/index.tsx index 37bbbece..6ac5820d 100644 --- a/packages/design-system/providers/ThemeProvider/index.tsx +++ b/packages/design-system/providers/ThemeProvider/index.tsx @@ -2,11 +2,11 @@ import { FC, useMemo } from 'react' +import { AppRouterCacheProvider } from '@mui/material-nextjs/v14-appRouter' import CssBaseline from '@mui/material/CssBaseline' import { ThemeProvider as MuiThemeProvider, createTheme } from '@mui/material/styles' import merge from 'lodash/merge' -import NextAppDirEmotionCacheProvider from '../../styles/material/next-emotion-cache' import { createContrast } from '../../styles/material/options/contrast' import { componentsOverrides } from '../../styles/material/overrides' import { createPresets } from '../../styles/presets' @@ -77,12 +77,12 @@ const ThemeProvider: FC = ({ theme.components = merge(componentsOverrides(theme), contrast.components, customOverrides) return ( - + {children} - + ) } diff --git a/packages/design-system/styles/material/next-emotion-cache.tsx b/packages/design-system/styles/material/next-emotion-cache.tsx deleted file mode 100644 index 89f3a9e5..00000000 --- a/packages/design-system/styles/material/next-emotion-cache.tsx +++ /dev/null @@ -1,97 +0,0 @@ -'use client' - -import * as React from 'react' - -import createCache from '@emotion/cache' -import type { EmotionCache, Options as OptionsOfCreateCache } from '@emotion/cache' -import { CacheProvider as DefaultCacheProvider } from '@emotion/react' -import { useServerInsertedHTML } from 'next/navigation' - -export type NextAppDirEmotionCacheProviderProps = { - /** This is the options passed to createCache() from 'import createCache from "@emotion/cache"' */ - options: Omit - /** By default from 'import { CacheProvider } from "@emotion/react"' */ - CacheProvider?: (props: { - value: EmotionCache - children: React.ReactNode - }) => React.JSX.Element | null - children: React.ReactNode -} - -// Adapted from https://github.com/garronej/tss-react/blob/main/src/next/appDir.tsx -export default function NextAppDirEmotionCacheProvider(props: NextAppDirEmotionCacheProviderProps) { - const { options, CacheProvider = DefaultCacheProvider, children } = props - - const [registry] = React.useState(() => { - const cache = createCache(options) - cache.compat = true - const prevInsert = cache.insert - let inserted: { name: string; isGlobal: boolean }[] = [] - cache.insert = (...args) => { - const [selector, serialized] = args - if (cache.inserted[serialized.name] === undefined) { - inserted.push({ - name: serialized.name, - isGlobal: !selector, - }) - } - return prevInsert(...args) - } - const flush = () => { - const prevInserted = inserted - inserted = [] - return prevInserted - } - return { cache, flush } - }) - - useServerInsertedHTML(() => { - const inserted = registry.flush() - if (inserted.length === 0) { - return null - } - let styles = '' - let dataEmotionAttribute = registry.cache.key - - const globals: { - name: string - style: string - }[] = [] - - inserted.forEach(({ name, isGlobal }) => { - const style = registry.cache.inserted[name] - - if (typeof style !== 'boolean') { - if (isGlobal) { - // @ts-ignore TODO: revisit this - globals.push({ name, style }) - } else { - styles += style - dataEmotionAttribute += ` ${name}` - } - } - }) - - return ( - <> - {globals.map(({ name, style }) => ( -