From ccac97aaea98edfc4c8f1340e8189de2efbcee1d Mon Sep 17 00:00:00 2001 From: Nick Leslie Date: Wed, 17 Jan 2024 16:58:28 -0500 Subject: [PATCH 1/3] Upping next to 14. Upping next-auth. Fixing lint errors --- .eslintrc.json | 6 +- .github/workflows/lint.yml | 60 ++ .github/workflows/test.yml | 4 +- README.md | 1 + next.config.mjs | 13 +- package.json | 13 +- pnpm-lock.yaml | 1272 ++++++++++++++++++--------- src/components/draw/DrawingArea.tsx | 8 +- src/components/ui/modal/Modal.tsx | 11 +- src/models/draw_event.model.ts | 7 +- src/pages/add_a_friend.tsx | 2 +- src/pages/api/auth/[...nextauth].ts | 1 - src/pages/draw.tsx | 6 +- src/pages/new_user.tsx | 1 - src/pages/sign_in.tsx | 6 +- src/pages/sign_out.tsx | 4 +- src/server/provider/global-ref.ts | 2 + src/server/services/user.service.ts | 2 +- src/server/wss-dev-server.ts | 5 - 19 files changed, 983 insertions(+), 441 deletions(-) create mode 100644 .github/workflows/lint.yml diff --git a/.eslintrc.json b/.eslintrc.json index 8370c13..657237f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -7,7 +7,9 @@ "extends": ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"], "rules": { "@typescript-eslint/consistent-type-imports": "warn", - "@typescript-eslint/ban-ts-comment": "warn", - "@typescript-eslint/no-empty-interface": "warn" + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/no-empty-interface": "warn", + "react-hooks/exhaustive-deps": "off", + "@next/next/no-img-element": "off" } } diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..cab9cb3 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,60 @@ +name: Lint +on: + push: + branches: [main] + paths-ignore: + [ + "documentation/**", + "public/**", + "docker-compose.yml", + "README.md", + "prettier.config.cjs", + ] + pull_request: + branches: [main] + paths-ignore: + [ + "documentation/**", + "public/**", + "docker-compose.yml", + "README.md", + "prettier.config.cjs", + ] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Use Node.js + uses: actions/setup-node@v4 + with: + node-version: 18.x + - uses: pnpm/action-setup@v2 + name: Install pnpm + with: + version: 8 + run_install: false + + - name: Get pnpm store directory + shell: bash + run: | + echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV + + - uses: actions/cache@v3 + name: Setup pnpm cache + with: + path: ${{ env.STORE_PATH }} + key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm-store- + + - name: Install dependencies + run: pnpm install + - name: Run lint + run: pnpm lint + continue-on-error: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1a26323..b614cc2 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,9 +44,9 @@ jobs: - 5932:5432 options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Use Node.js - uses: actions/setup-node@v1 + uses: actions/setup-node@v4 with: node-version: 18.x - uses: pnpm/action-setup@v2 diff --git a/README.md b/README.md index a211768..d4bdf4a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Draw for them [![Test Backend](https://github.com/ncpleslie/draw-for-them/actions/workflows/test.yml/badge.svg)](https://github.com/ncpleslie/draw-for-them/actions/workflows/test.yml) +[![Test Results](https://camo.githubusercontent.com/6849be041b20ce8af9bee400d999597859f3f329f788e32ad13b93a8190e259c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f32352f32352d5041535345442d627269676874677265656e2e737667)](https://camo.githubusercontent.com/6849be041b20ce8af9bee400d999597859f3f329f788e32ad13b93a8190e259c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f32352f32352d5041535345442d627269676874677265656e2e737667) ![Image of the draw for you application](./documentation/draw_for_them_showcase.png) diff --git a/next.config.mjs b/next.config.mjs index 075a9ed..4167d67 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,4 @@ -// @ts-check +// @ts-nocheck /** * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. * This is especially useful for Docker builds. @@ -23,8 +23,9 @@ const config = { }, }; -export default withSuperjson()( - withPWA({ disable: process.env.NODE_ENV === "development", dest: "public" })( - config - ) -); +const pwa = withPWA({ + disable: process.env.NODE_ENV === "development", + dest: "public", +})(config); + +export default withSuperjson()(pwa); diff --git a/package.json b/package.json index bbbe8fe..aebf188 100644 --- a/package.json +++ b/package.json @@ -45,11 +45,10 @@ "fabric": "github:ncpleslie/fabric.js", "fabricjs-react": "github:ncpleslie/fabricjs-react", "firebase-admin": "11.5.0", - "next": "13.0.2", - "next-auth": "4.15.1", + "next": "14.0.4", + "next-auth": "4.24.5", "next-pwa": "5.6.0", "next-superjson": "0.0.4", - "node-fetch": "3.3.0", "nodemailer": "6.9.7", "prisma": "4.9.0", "react": "18.2.0", @@ -59,7 +58,7 @@ "resend": "^2.0.0", "superjson": "1.9.1", "ws": "8.11.0", - "zod": "3.20.2", + "zod": "3.22.4", "zustand": "4.3.2" }, "devDependencies": { @@ -69,15 +68,15 @@ "@types/next-pwa": "^5.6.2", "@types/node": "^18.11.9", "@types/nodemailer": "^6.4.7", - "@types/react": "^18.0.25", - "@types/react-dom": "^18.0.9", + "@types/react": "^18.2.48", + "@types/react-dom": "^18.2.18", "@types/ws": "^8.5.3", "@typescript-eslint/eslint-plugin": "^5.43.0", "@typescript-eslint/parser": "^5.43.0", "autoprefixer": "^10.4.13", "cross-env": "^7.0.3", "eslint": "^8.28.0", - "eslint-config-next": "13.0.2", + "eslint-config-next": "14.0.4", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", "nodemon": "^2.0.20", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 11b8cda..510c58b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -22,7 +22,7 @@ dependencies: version: 1.7.4(react-dom@18.2.0)(react@18.2.0) '@next-auth/prisma-adapter': specifier: 1.0.4 - version: 1.0.4(@prisma/client@4.9.0)(next-auth@4.15.1) + version: 1.0.4(@prisma/client@4.9.0)(next-auth@4.24.5) '@prisma/client': specifier: 4.9.0 version: 4.9.0(prisma@4.9.0) @@ -34,7 +34,7 @@ dependencies: version: 10.0.0-rc.4(@trpc/server@10.0.0-rc.4) '@trpc/next': specifier: 10.0.0-rc.4 - version: 10.0.0-rc.4(@tanstack/react-query@4.10.0)(@trpc/client@10.0.0-rc.4)(@trpc/react-query@10.0.0-rc.4)(@trpc/server@10.0.0-rc.4)(next@13.0.2)(react-dom@18.2.0)(react@18.2.0) + version: 10.0.0-rc.4(@tanstack/react-query@4.10.0)(@trpc/client@10.0.0-rc.4)(@trpc/react-query@10.0.0-rc.4)(@trpc/server@10.0.0-rc.4)(next@14.0.4)(react-dom@18.2.0)(react@18.2.0) '@trpc/react-query': specifier: 10.0.0-rc.4 version: 10.0.0-rc.4(@tanstack/react-query@4.10.0)(@trpc/client@10.0.0-rc.4)(@trpc/server@10.0.0-rc.4)(react-dom@18.2.0)(react@18.2.0) @@ -54,20 +54,17 @@ dependencies: specifier: 11.5.0 version: 11.5.0 next: - specifier: 13.0.2 - version: 13.0.2(@babel/core@7.23.6)(react-dom@18.2.0)(react@18.2.0) + specifier: 14.0.4 + version: 14.0.4(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0) next-auth: - specifier: 4.15.1 - version: 4.15.1(next@13.0.2)(nodemailer@6.9.7)(react-dom@18.2.0)(react@18.2.0) + specifier: 4.24.5 + version: 4.24.5(next@14.0.4)(nodemailer@6.9.7)(react-dom@18.2.0)(react@18.2.0) next-pwa: specifier: 5.6.0 - version: 5.6.0(@babel/core@7.23.6)(next@13.0.2)(webpack@5.89.0) + version: 5.6.0(@babel/core@7.23.7)(next@14.0.4)(webpack@5.89.0) next-superjson: specifier: 0.0.4 - version: 0.0.4(next@13.0.2)(superjson@1.9.1)(webpack@5.89.0) - node-fetch: - specifier: 3.3.0 - version: 3.3.0 + version: 0.0.4(next@14.0.4)(superjson@1.9.1)(webpack@5.89.0) nodemailer: specifier: 6.9.7 version: 6.9.7 @@ -96,8 +93,8 @@ dependencies: specifier: 8.11.0 version: 8.11.0 zod: - specifier: 3.20.2 - version: 3.20.2 + specifier: 3.22.4 + version: 3.22.4 zustand: specifier: 4.3.2 version: 4.3.2(react@18.2.0) @@ -114,7 +111,7 @@ devDependencies: version: 29.5.11 '@types/next-pwa': specifier: ^5.6.2 - version: 5.6.2(@babel/core@7.23.6)(react-dom@18.2.0)(react@18.2.0) + version: 5.6.2(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0) '@types/node': specifier: ^18.11.9 version: 18.11.9 @@ -122,11 +119,11 @@ devDependencies: specifier: ^6.4.7 version: 6.4.7 '@types/react': - specifier: ^18.0.25 - version: 18.0.25 + specifier: ^18.2.48 + version: 18.2.48 '@types/react-dom': - specifier: ^18.0.9 - version: 18.0.9 + specifier: ^18.2.18 + version: 18.2.18 '@types/ws': specifier: ^8.5.3 version: 8.5.3 @@ -146,8 +143,8 @@ devDependencies: specifier: ^8.28.0 version: 8.28.0 eslint-config-next: - specifier: 13.0.2 - version: 13.0.2(eslint@8.28.0)(typescript@4.9.3) + specifier: 14.0.4 + version: 14.0.4(eslint@8.28.0)(typescript@4.9.3) jest: specifier: ^29.7.0 version: 29.7.0(@types/node@18.11.9)(ts-node@10.9.1) @@ -280,6 +277,29 @@ packages: semver: 6.3.1 transitivePeerDependencies: - supports-color + dev: true + + /@babel/core@7.23.7: + resolution: {integrity: sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.6 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) + '@babel/helpers': 7.23.8 + '@babel/parser': 7.23.6 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.7 + '@babel/types': 7.23.6 + convert-source-map: 2.0.0 + debug: 4.3.4 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color /@babel/generator@7.20.14: resolution: {integrity: sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==} @@ -462,6 +482,20 @@ packages: '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 /@babel/helper-optimise-call-expression@7.18.6: resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==} @@ -585,6 +619,17 @@ packages: '@babel/types': 7.23.6 transitivePeerDependencies: - supports-color + dev: true + + /@babel/helpers@7.23.8: + resolution: {integrity: sha512-KDqYz4PiOWvDFrdHLPhKtCThtIcKVy6avWD2oG4GEvyQ+XDZwHD4YQd+H2vNMnq2rkdxsDkU82T+Vk8U/WXHRQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.7 + '@babel/types': 7.23.6 + transitivePeerDependencies: + - supports-color /@babel/highlight@7.18.6: resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} @@ -1507,19 +1552,17 @@ packages: /@babel/regjsgen@0.8.0: resolution: {integrity: sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==} - /@babel/runtime-corejs3@7.20.1: - resolution: {integrity: sha512-CGulbEDcg/ND1Im7fUNRZdGXmX2MTWVVZacQi/6DiKE5HNwZ3aVTm5PV4lO8HHz0B2h8WQyvKKjbX5XgTtydsg==} + /@babel/runtime@7.20.1: + resolution: {integrity: sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==} engines: {node: '>=6.9.0'} dependencies: - core-js-pure: 3.26.1 regenerator-runtime: 0.13.11 - dev: true - /@babel/runtime@7.20.1: - resolution: {integrity: sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg==} + /@babel/runtime@7.23.8: + resolution: {integrity: sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw==} engines: {node: '>=6.9.0'} dependencies: - regenerator-runtime: 0.13.11 + regenerator-runtime: 0.14.1 /@babel/template@7.20.7: resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} @@ -1570,6 +1613,24 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color + dev: true + + /@babel/traverse@7.23.7: + resolution: {integrity: sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.6 + '@babel/types': 7.23.6 + debug: 4.3.4 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color /@babel/types@7.21.0: resolution: {integrity: sha512-uR7NWq2VNFnDi7EYqiRz2Jv/VQIu38tu64Zy8TX2nQFQ6etJ9V/Rr2msW8BS132mum2rL645qpDrLtAJtVpuow==} @@ -2164,7 +2225,7 @@ packages: resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} dependencies: '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.20 + '@jridgewell/trace-mapping': 0.3.21 dev: false /@jridgewell/sourcemap-codec@1.4.14: @@ -2185,6 +2246,13 @@ packages: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + /@jridgewell/trace-mapping@0.3.21: + resolution: {integrity: sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: false + /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: @@ -2221,127 +2289,190 @@ packages: dev: false optional: true - /@next-auth/prisma-adapter@1.0.4(@prisma/client@4.9.0)(next-auth@4.15.1): + /@next-auth/prisma-adapter@1.0.4(@prisma/client@4.9.0)(next-auth@4.24.5): resolution: {integrity: sha512-jIOM6CzCbl2/Mzbx9kb2IjtHoJOeRN9wtQgLk4EUm5bhneSVGv1rtz5TDskvp2UfCa+EK9nDmug+lje41z80Gg==} peerDependencies: '@prisma/client': '>=2.26.0 || >=3' next-auth: ^4 dependencies: '@prisma/client': 4.9.0(prisma@4.9.0) - next-auth: 4.15.1(next@13.0.2)(nodemailer@6.9.7)(react-dom@18.2.0)(react@18.2.0) + next-auth: 4.24.5(next@14.0.4)(nodemailer@6.9.7)(react-dom@18.2.0)(react@18.2.0) dev: false - /@next/env@13.0.2: - resolution: {integrity: sha512-Qb6WPuRriGIQ19qd6NBxpcrFOfj8ziN7l9eZUfwff5gl4zLXluqtuZPddYZM/oWjN53ZYcuRXzL+oowKyJeYtA==} + /@next/env@13.5.6: + resolution: {integrity: sha512-Yac/bV5sBGkkEXmAX5FWPS9Mmo2rthrOPRQQNfycJPkjUAUclomCPH7QFVCDQ4Mp2k2K1SSM6m0zrxYrOwtFQw==} + dev: true + + /@next/env@14.0.4: + resolution: {integrity: sha512-irQnbMLbUNQpP1wcE5NstJtbuA/69kRfzBrpAD7Gsn8zm/CY6YQYc3HQBz8QPxwISG26tIm5afvvVbu508oBeQ==} + dev: false - /@next/eslint-plugin-next@13.0.2: - resolution: {integrity: sha512-W+fIIIaFU7Kct7Okx91C7XDRGolv/w2RUenX2yZFeeNVcuVzDIKUcNmckrYbYcwrNQUSXmtwrs3g8xwast0YtA==} + /@next/eslint-plugin-next@14.0.4: + resolution: {integrity: sha512-U3qMNHmEZoVmHA0j/57nRfi3AscXNvkOnxDmle/69Jz/G0o/gWjXTDdlgILZdrxQ0Lw/jv2mPW8PGy0EGIHXhQ==} dependencies: glob: 7.1.7 dev: true - /@next/swc-android-arm-eabi@13.0.2: - resolution: {integrity: sha512-X54UQCTFyOGnJP//Z71dPPlp4BCYcQL2ncikKXQcPzVpqPs4C3m+tKC8ivBNH6edAXkppwsLRz1/yQwgSZ9Swg==} + /@next/swc-darwin-arm64@13.5.6: + resolution: {integrity: sha512-5nvXMzKtZfvcu4BhtV0KH1oGv4XEW+B+jOfmBdpFI3C7FrB/MfujRpWYSBBO64+qbW8pkZiSyQv9eiwnn5VIQA==} engines: {node: '>= 10'} - cpu: [arm] - os: [android] + cpu: [arm64] + os: [darwin] requiresBuild: true + dev: true optional: true - /@next/swc-android-arm64@13.0.2: - resolution: {integrity: sha512-1P00Kv8uKaLubqo7JzPrTqgFAzSOmfb8iwqJrOb9in5IvTRtNGlkR4hU0sXzqbQNM/+SaYxze6Z5ry1IDyb/cQ==} + /@next/swc-darwin-arm64@14.0.4: + resolution: {integrity: sha512-mF05E/5uPthWzyYDyptcwHptucf/jj09i2SXBPwNzbgBNc+XnwzrL0U6BmPjQeOL+FiB+iG1gwBeq7mlDjSRPg==} engines: {node: '>= 10'} cpu: [arm64] - os: [android] + os: [darwin] requiresBuild: true + dev: false optional: true - /@next/swc-darwin-arm64@13.0.2: - resolution: {integrity: sha512-1zGIOkInkOLRv0QQGZ+3wffYsyKI4vIy62LYTvDWUn7TAYqnmXwougp9NSLqDeagLwgsv2URrykyAFixA/YqxA==} + /@next/swc-darwin-x64@13.5.6: + resolution: {integrity: sha512-6cgBfxg98oOCSr4BckWjLLgiVwlL3vlLj8hXg2b+nDgm4bC/qVXXLfpLB9FHdoDu4057hzywbxKvmYGmi7yUzA==} engines: {node: '>= 10'} - cpu: [arm64] + cpu: [x64] os: [darwin] requiresBuild: true + dev: true optional: true - /@next/swc-darwin-x64@13.0.2: - resolution: {integrity: sha512-ECDAjoMP1Y90cARaelS6X+k6BQx+MikAYJ8f/eaJrLur44NIOYc9HA/dgcTp5jenguY4yT8V+HCquLjAVle6fA==} + /@next/swc-darwin-x64@14.0.4: + resolution: {integrity: sha512-IZQ3C7Bx0k2rYtrZZxKKiusMTM9WWcK5ajyhOZkYYTCc8xytmwSzR1skU7qLgVT/EY9xtXDG0WhY6fyujnI3rw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] requiresBuild: true + dev: false optional: true - /@next/swc-freebsd-x64@13.0.2: - resolution: {integrity: sha512-2DcL/ofQdBnQX3IoI9sjlIAyLCD1oZoUBuhrhWbejvBQjutWrI0JTEv9uG69WcxWhVMm3BCsjv8GK2/68OKp7A==} + /@next/swc-linux-arm64-gnu@13.5.6: + resolution: {integrity: sha512-txagBbj1e1w47YQjcKgSU4rRVQ7uF29YpnlHV5xuVUsgCUf2FmyfJ3CPjZUvpIeXCJAoMCFAoGnbtX86BK7+sg==} engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] + cpu: [arm64] + os: [linux] requiresBuild: true + dev: true optional: true - /@next/swc-linux-arm-gnueabihf@13.0.2: - resolution: {integrity: sha512-Y3OQF1CSBSWW2vGkmvOIuOUNqOq8qX7f1ZpcKUVWP3/Uq++DZmVi9d18lgnSe1I3QFqc+nXWyun9ljsN83j0sw==} + /@next/swc-linux-arm64-gnu@14.0.4: + resolution: {integrity: sha512-VwwZKrBQo/MGb1VOrxJ6LrKvbpo7UbROuyMRvQKTFKhNaXjUmKTu7wxVkIuCARAfiI8JpaWAnKR+D6tzpCcM4w==} engines: {node: '>= 10'} - cpu: [arm] + cpu: [arm64] os: [linux] requiresBuild: true + dev: false optional: true - /@next/swc-linux-arm64-gnu@13.0.2: - resolution: {integrity: sha512-mNyzwsFF6kwZYEjnGicx9ksDZYEZvyzEc1BtCu8vdZi/v8UeixQwCiAT6FyYX9uxMPEkzk8qiU0t0u9gvltsKw==} + /@next/swc-linux-arm64-musl@13.5.6: + resolution: {integrity: sha512-cGd+H8amifT86ZldVJtAKDxUqeFyLWW+v2NlBULnLAdWsiuuN8TuhVBt8ZNpCqcAuoruoSWynvMWixTFcroq+Q==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] requiresBuild: true + dev: true optional: true - /@next/swc-linux-arm64-musl@13.0.2: - resolution: {integrity: sha512-M6SdYjWgRrY3tJBxz0663zCRPTu5BRONmxlftKWWHv9LjAJ59neTLaGj4rp0A08DkJglZIoCkLOzLrzST6TGag==} + /@next/swc-linux-arm64-musl@14.0.4: + resolution: {integrity: sha512-8QftwPEW37XxXoAwsn+nXlodKWHfpMaSvt81W43Wh8dv0gkheD+30ezWMcFGHLI71KiWmHK5PSQbTQGUiidvLQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] requiresBuild: true + dev: false + optional: true + + /@next/swc-linux-x64-gnu@13.5.6: + resolution: {integrity: sha512-Mc2b4xiIWKXIhBy2NBTwOxGD3nHLmq4keFk+d4/WL5fMsB8XdJRdtUlL87SqVCTSaf1BRuQQf1HvXZcy+rq3Nw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@next/swc-linux-x64-gnu@14.0.4: + resolution: {integrity: sha512-/s/Pme3VKfZAfISlYVq2hzFS8AcAIOTnoKupc/j4WlvF6GQ0VouS2Q2KEgPuO1eMBwakWPB1aYFIA4VNVh667A==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false optional: true - /@next/swc-linux-x64-gnu@13.0.2: - resolution: {integrity: sha512-pi63RoxvG4ES1KS06Zpm0MATVIXTs/TIbLbdckeLoM40u1d3mQl/+hSSrLRSxzc2OtyL8fh92sM4gkJrQXAMAw==} + /@next/swc-linux-x64-musl@13.5.6: + resolution: {integrity: sha512-CFHvP9Qz98NruJiUnCe61O6GveKKHpJLloXbDSWRhqhkJdZD2zU5hG+gtVJR//tyW897izuHpM6Gtf6+sNgJPQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] requiresBuild: true + dev: true optional: true - /@next/swc-linux-x64-musl@13.0.2: - resolution: {integrity: sha512-9Pv91gfYnDONgjtRm78n64b/c54+azeHtlnqBLTnIFWSMBDRl1/WDkhKWIj3fBGPLimtK7Tko3ULR3og9RRUPw==} + /@next/swc-linux-x64-musl@14.0.4: + resolution: {integrity: sha512-m8z/6Fyal4L9Bnlxde5g2Mfa1Z7dasMQyhEhskDATpqr+Y0mjOBZcXQ7G5U+vgL22cI4T7MfvgtrM2jdopqWaw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] requiresBuild: true + dev: false + optional: true + + /@next/swc-win32-arm64-msvc@13.5.6: + resolution: {integrity: sha512-aFv1ejfkbS7PUa1qVPwzDHjQWQtknzAZWGTKYIAaS4NMtBlk3VyA6AYn593pqNanlicewqyl2jUhQAaFV/qXsg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true optional: true - /@next/swc-win32-arm64-msvc@13.0.2: - resolution: {integrity: sha512-Nvewe6YZaizAkGHHprbMkYqQulBjZCHKBGKeFPwoPtOA+a2Qi4pZzc/qXFyC5/2A6Z0mr2U1zg9rd04WBYMwBw==} + /@next/swc-win32-arm64-msvc@14.0.4: + resolution: {integrity: sha512-7Wv4PRiWIAWbm5XrGz3D8HUkCVDMMz9igffZG4NB1p4u1KoItwx9qjATHz88kwCEal/HXmbShucaslXCQXUM5w==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] requiresBuild: true + dev: false + optional: true + + /@next/swc-win32-ia32-msvc@13.5.6: + resolution: {integrity: sha512-XqqpHgEIlBHvzwG8sp/JXMFkLAfGLqkbVsyN+/Ih1mR8INb6YCc2x/Mbwi6hsAgUnqQztz8cvEbHJUbSl7RHDg==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true optional: true - /@next/swc-win32-ia32-msvc@13.0.2: - resolution: {integrity: sha512-ZUBYGZw5G3QrqDpRq1EWi3aHmvPZM8ijK5TFL6UbH16cYQ0JpANmuG2P66KB93Qe/lWWzbeAZk/tj1XqwoCuPA==} + /@next/swc-win32-ia32-msvc@14.0.4: + resolution: {integrity: sha512-zLeNEAPULsl0phfGb4kdzF/cAVIfaC7hY+kt0/d+y9mzcZHsMS3hAS829WbJ31DkSlVKQeHEjZHIdhN+Pg7Gyg==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] requiresBuild: true + dev: false + optional: true + + /@next/swc-win32-x64-msvc@13.5.6: + resolution: {integrity: sha512-Cqfe1YmOS7k+5mGu92nl5ULkzpKuxJrP3+4AEuPmrpFZ3BHxTY3TnHmU1On3bFmFFs6FbTcdF58CCUProGpIGQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true optional: true - /@next/swc-win32-x64-msvc@13.0.2: - resolution: {integrity: sha512-fA9uW1dm7C0mEYGcKlbmLcVm2sKcye+1kPxh2cM4jVR+kQQMtHWsjIzeSpe2grQLSDan06z4n6hbr8b1c3hA8w==} + /@next/swc-win32-x64-msvc@14.0.4: + resolution: {integrity: sha512-yEh2+R8qDlDCjxVpzOTEpBLQTEFAcP2A8fUFLaWNap9GitYKkKv1//y2S6XY6zsR4rCOPRpU7plYDR+az2n30A==} engines: {node: '>= 10'} cpu: [x64] os: [win32] requiresBuild: true + dev: false optional: true /@nodelib/fs.scandir@2.1.5: @@ -2366,8 +2497,8 @@ packages: resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} dev: false - /@panva/hkdf@1.0.2: - resolution: {integrity: sha512-MSAs9t3Go7GUkMhpKC44T58DJ5KGk2vBo+h1cqQeqlMfdGkxaVB78ZWpv9gYi/g2fa4sopag9gJsNvS8XGgWJA==} + /@panva/hkdf@1.1.1: + resolution: {integrity: sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==} dev: false /@pkgjs/parseargs@0.11.0: @@ -2523,8 +2654,8 @@ packages: picomatch: 2.3.1 rollup: 2.79.1 - /@rushstack/eslint-patch@1.2.0: - resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==} + /@rushstack/eslint-patch@1.7.0: + resolution: {integrity: sha512-Jh4t/593gxs0lJZ/z3NnasKlplXT2f+4y/LZYuaKZW5KAaiVFL/fThhs+17EbUd53jUVJ0QudYCBGbN/psvaqg==} dev: true /@selderee/plugin-htmlparser2@0.11.0: @@ -2558,10 +2689,10 @@ packages: magic-string: 0.25.9 string.prototype.matchall: 4.0.8 - /@swc/helpers@0.4.11: - resolution: {integrity: sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==} + /@swc/helpers@0.5.2: + resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} dependencies: - tslib: 2.4.1 + tslib: 2.6.2 /@tanstack/query-core@4.10.0: resolution: {integrity: sha512-BlBgA6Js2bE7qHS7KPH2nAgoPpItXxPqM5FHIcgXemhHJTky12snnpOPluoCA9jumR0wYySain/OR4ihjtWUNQ==} @@ -2638,7 +2769,7 @@ packages: dependencies: '@babel/runtime': 7.20.1 '@testing-library/dom': 9.3.4 - '@types/react-dom': 18.0.9 + '@types/react-dom': 18.2.18 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: true @@ -2656,7 +2787,7 @@ packages: '@trpc/server': 10.0.0-rc.4 dev: false - /@trpc/next@10.0.0-rc.4(@tanstack/react-query@4.10.0)(@trpc/client@10.0.0-rc.4)(@trpc/react-query@10.0.0-rc.4)(@trpc/server@10.0.0-rc.4)(next@13.0.2)(react-dom@18.2.0)(react@18.2.0): + /@trpc/next@10.0.0-rc.4(@tanstack/react-query@4.10.0)(@trpc/client@10.0.0-rc.4)(@trpc/react-query@10.0.0-rc.4)(@trpc/server@10.0.0-rc.4)(next@14.0.4)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-i9lynpSeBxZnEVqALNQVWidlQbagsLGP+IIWILV7x70ltZI8A+k2T1bwfd+ZhS6Mj1Avp0bvW2sB0psfS8pE5g==} peerDependencies: '@tanstack/react-query': ^4.3.8 @@ -2671,7 +2802,7 @@ packages: '@trpc/client': 10.0.0-rc.4(@trpc/server@10.0.0-rc.4) '@trpc/react-query': 10.0.0-rc.4(@tanstack/react-query@4.10.0)(@trpc/client@10.0.0-rc.4)(@trpc/server@10.0.0-rc.4)(react-dom@18.2.0)(react@18.2.0) '@trpc/server': 10.0.0-rc.4 - next: 13.0.2(@babel/core@7.23.6)(react-dom@18.2.0)(react@18.2.0) + next: 14.0.4(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-ssr-prepass: 1.5.0(react@18.2.0) @@ -2762,12 +2893,12 @@ packages: /@types/eslint-scope@3.7.7: resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} dependencies: - '@types/eslint': 8.44.9 + '@types/eslint': 8.56.2 '@types/estree': 1.0.5 dev: false - /@types/eslint@8.44.9: - resolution: {integrity: sha512-6yBxcvwnnYoYT1Uk2d+jvIfsuP4mb2EdIxFnrPABj5a/838qe5bGkNLFOiipX4ULQ7XVQvTxOh7jO+BTAiqsEw==} + /@types/eslint@8.56.2: + resolution: {integrity: sha512-uQDwm1wFHmbBbCZCqAlq6Do9LYwByNZHWzXppSnay9SuwJ+VRbjkbLABer54kcPnMSlG6Fdiy2yaFXm/z9Z5gw==} dependencies: '@types/estree': 1.0.5 '@types/json-schema': 7.0.15 @@ -2902,18 +3033,17 @@ packages: resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} dev: false - /@types/next-pwa@5.6.2(@babel/core@7.23.6)(react-dom@18.2.0)(react@18.2.0): + /@types/next-pwa@5.6.2(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-K5zLZSzrJCOQBay5E7abGp7gQ0q1Pv58dE3RuBo5LQXYQFaCO4JPju0XYdzgLoQ20yhBVZ43AwIcSgCzx9KvqA==} dependencies: - '@types/react': 18.0.25 - next: 13.0.2(@babel/core@7.23.6)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.48 + next: 13.5.6(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0) workbox-build: 6.5.4 transitivePeerDependencies: - '@babel/core' + - '@opentelemetry/api' - '@types/babel__core' - babel-plugin-macros - - fibers - - node-sass - react - react-dom - sass @@ -2941,14 +3071,14 @@ packages: resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} dev: false - /@types/react-dom@18.0.9: - resolution: {integrity: sha512-qnVvHxASt/H7i+XG1U1xMiY5t+IHcPGUK7TDMDzom08xa7e86eCeKOiLZezwCKVxJn6NEiiy2ekgX8aQssjIKg==} + /@types/react-dom@18.2.18: + resolution: {integrity: sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==} dependencies: - '@types/react': 18.0.25 + '@types/react': 18.2.48 dev: true - /@types/react@18.0.25: - resolution: {integrity: sha512-xD6c0KDT4m7n9uD4ZHi02lzskaiqcBxf4zi+tXZY98a04wvc0hi/TcCPC2FOESZi51Nd7tlUeOJY8RofL799/g==} + /@types/react@18.2.48: + resolution: {integrity: sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==} dependencies: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 @@ -3292,12 +3422,12 @@ packages: acorn-walk: 8.2.0 dev: true - /acorn-import-assertions@1.9.0(acorn@8.11.2): + /acorn-import-assertions@1.9.0(acorn@8.11.3): resolution: {integrity: sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==} peerDependencies: acorn: ^8 dependencies: - acorn: 8.11.2 + acorn: 8.11.3 dev: false /acorn-jsx@5.3.2(acorn@8.11.2): @@ -3344,6 +3474,12 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + /acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: false + /acorn@8.8.1: resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} engines: {node: '>=0.4.0'} @@ -3462,14 +3598,6 @@ packages: /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - /aria-query@4.2.2: - resolution: {integrity: sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==} - engines: {node: '>=6.0'} - dependencies: - '@babel/runtime': 7.20.1 - '@babel/runtime-corejs3': 7.20.1 - dev: true - /aria-query@5.1.3: resolution: {integrity: sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==} dependencies: @@ -3489,14 +3617,14 @@ packages: is-array-buffer: 3.0.2 dev: true - /array-includes@3.1.6: - resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} + /array-includes@3.1.7: + resolution: {integrity: sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 - get-intrinsic: 1.1.3 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 is-string: 1.0.7 dev: true @@ -3516,34 +3644,58 @@ packages: engines: {node: '>=0.10.0'} dev: false - /array.prototype.flat@1.3.1: - resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} + /array.prototype.findlastindex@1.2.3: + resolution: {integrity: sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 - es-shim-unscopables: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + get-intrinsic: 1.2.2 dev: true - /array.prototype.flatmap@1.3.1: - resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 - es-shim-unscopables: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 dev: true - /array.prototype.tosorted@1.1.1: - resolution: {integrity: sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==} + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 - es-shim-unscopables: 1.0.0 - get-intrinsic: 1.1.3 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + dev: true + + /array.prototype.tosorted@1.1.2: + resolution: {integrity: sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-shim-unscopables: 1.0.2 + get-intrinsic: 1.2.2 + dev: true + + /arraybuffer.prototype.slice@1.0.2: + resolution: {integrity: sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + is-array-buffer: 3.0.2 + is-shared-array-buffer: 1.0.2 dev: true /arrify@2.0.1: @@ -3553,8 +3705,8 @@ packages: dev: false optional: true - /ast-types-flow@0.0.7: - resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} + /ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} dev: true /async-retry@1.3.3: @@ -3568,6 +3720,12 @@ packages: /async@3.2.4: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} + /asynciterator.prototype@1.0.0: + resolution: {integrity: sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==} + dependencies: + has-symbols: 1.0.3 + dev: true + /asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} requiresBuild: true @@ -3597,13 +3755,15 @@ packages: engines: {node: '>= 0.4'} dev: true - /axe-core@4.5.2: - resolution: {integrity: sha512-u2MVsXfew5HBvjsczCv+xlwdNnB1oQR9HlAcsejZttNjKKSkeDNVwB1vMThIUIFI9GoT57Vtk8iQLwqOfAkboA==} + /axe-core@4.7.0: + resolution: {integrity: sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==} engines: {node: '>=4'} dev: true - /axobject-query@2.2.0: - resolution: {integrity: sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==} + /axobject-query@3.2.1: + resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} + dependencies: + dequal: 2.0.3 dev: true /babel-jest@29.7.0(@babel/core@7.23.6): @@ -3639,14 +3799,14 @@ packages: webpack: 5.89.0 dev: false - /babel-loader@8.3.0(@babel/core@7.23.6)(webpack@5.89.0): + /babel-loader@8.3.0(@babel/core@7.23.7)(webpack@5.89.0): resolution: {integrity: sha512-H8SvsMF+m9t15HNLMipppzkC+Y2Yq+v3SonZyU70RBL/h1gxPkH08Ot8pEE9Z4Kd+czyWJClmFS8qzIP9OZ04Q==} engines: {node: '>= 8.9'} peerDependencies: '@babel/core': ^7.0.0 webpack: '>=2' dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 find-cache-dir: 3.3.2 loader-utils: 2.0.4 make-dir: 3.1.0 @@ -3710,7 +3870,7 @@ packages: transitivePeerDependencies: - supports-color - /babel-plugin-superjson-next@0.4.5(next@13.0.2)(superjson@1.9.1): + /babel-plugin-superjson-next@0.4.5(next@14.0.4)(superjson@1.9.1): resolution: {integrity: sha512-k7S99Qpsbi3OSdlCMXEiklzxepM6QbYEIUsrjgSkpx+ksT0iNfdY2r1kCzBK2UjG8fLN6NZEKpDA8XpG2pbDSA==} engines: {node: '>=10'} peerDependencies: @@ -3720,7 +3880,7 @@ packages: '@babel/helper-module-imports': 7.18.6 '@babel/types': 7.21.0 hoist-non-react-statics: 3.3.2 - next: 13.0.2(@babel/core@7.23.6)(react-dom@18.2.0)(react@18.2.0) + next: 14.0.4(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0) superjson: 1.9.1 dev: false @@ -3824,7 +3984,7 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001568 + caniuse-lite: 1.0.30001578 electron-to-chromium: 1.4.284 node-releases: 2.0.10 update-browserslist-db: 1.0.10(browserslist@4.21.5) @@ -3834,7 +3994,7 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001568 + caniuse-lite: 1.0.30001578 electron-to-chromium: 1.4.611 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.2) @@ -3856,6 +4016,12 @@ packages: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} engines: {node: '>=6'} + /busboy@1.6.0: + resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==} + engines: {node: '>=10.16.0'} + dependencies: + streamsearch: 1.1.0 + /call-bind@1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: @@ -3891,6 +4057,10 @@ packages: /caniuse-lite@1.0.30001568: resolution: {integrity: sha512-vSUkH84HontZJ88MiNrOau1EBrCqEQYgkC5gIySiDlpsm8sGVrhU7Kx4V6h0tnqaHzIHZv08HlJIwPbL4XL9+A==} + dev: true + + /caniuse-lite@1.0.30001578: + resolution: {integrity: sha512-J/jkFgsQ3NEl4w2lCoM9ZPxrD+FoBNJ7uJUpGVjIg/j0OwJosWM36EPDv+Yyi0V4twBk9pPmlFS+PLykgEvUmg==} /canvas@2.11.2: resolution: {integrity: sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==} @@ -4124,11 +4294,6 @@ packages: dependencies: browserslist: 4.21.5 - /core-js-pure@3.26.1: - resolution: {integrity: sha512-VVXcDpp/xJ21KdULRq/lXdLzQAtX7+37LzpyfFM973il0tWSsDEoyzG38G14AjTpK9VTfiNM9jnFauq/CpaWGQ==} - requiresBuild: true - dev: true - /create-jest@29.7.0(@types/node@18.11.9)(ts-node@10.9.1): resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -4216,11 +4381,6 @@ packages: resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} dev: true - /data-uri-to-buffer@4.0.0: - resolution: {integrity: sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==} - engines: {node: '>= 12'} - dev: false - /data-urls@3.0.2: resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} engines: {node: '>=12'} @@ -4230,17 +4390,6 @@ packages: whatwg-mimetype: 3.0.0 whatwg-url: 11.0.0 - /debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.0.0 - dev: true - /debug@3.2.7(supports-color@5.5.0): resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -4562,7 +4711,6 @@ packages: dependencies: graceful-fs: 4.2.11 tapable: 2.2.1 - dev: false /ent@2.2.0: resolution: {integrity: sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==} @@ -4615,6 +4763,51 @@ packages: string.prototype.trimstart: 1.0.6 unbox-primitive: 1.0.2 + /es-abstract@1.22.3: + resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.0 + arraybuffer.prototype.slice: 1.0.2 + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + es-set-tostringtag: 2.0.2 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.2 + get-symbol-description: 1.0.0 + globalthis: 1.0.3 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + internal-slot: 1.0.6 + is-array-buffer: 3.0.2 + is-callable: 1.2.7 + is-negative-zero: 2.0.2 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.2 + is-string: 1.0.7 + is-typed-array: 1.1.12 + is-weakref: 1.0.2 + object-inspect: 1.13.1 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.1 + safe-array-concat: 1.1.0 + safe-regex-test: 1.0.2 + string.prototype.trim: 1.2.8 + string.prototype.trimend: 1.0.7 + string.prototype.trimstart: 1.0.7 + typed-array-buffer: 1.0.0 + typed-array-byte-length: 1.0.0 + typed-array-byte-offset: 1.0.0 + typed-array-length: 1.0.4 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.13 + dev: true + /es-get-iterator@1.1.3: resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} dependencies: @@ -4629,19 +4822,47 @@ packages: stop-iteration-iterator: 1.0.0 dev: true + /es-iterator-helpers@1.0.15: + resolution: {integrity: sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==} + dependencies: + asynciterator.prototype: 1.0.0 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + es-set-tostringtag: 2.0.2 + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + has-property-descriptors: 1.0.1 + has-proto: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + iterator.prototype: 1.1.2 + safe-array-concat: 1.1.0 + dev: true + /es-module-lexer@1.4.1: resolution: {integrity: sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w==} dev: false - /es-shim-unscopables@1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} + /es-set-tostringtag@2.0.2: + resolution: {integrity: sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==} + engines: {node: '>= 0.4'} dependencies: - has: 1.0.3 + get-intrinsic: 1.2.2 + has-tostringtag: 1.0.0 + hasown: 2.0.0 dev: true - /es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + dependencies: + hasown: 2.0.0 + dev: true + + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} dependencies: is-callable: 1.2.7 is-date-object: 1.0.5 @@ -4903,8 +5124,8 @@ packages: optionalDependencies: source-map: 0.6.1 - /eslint-config-next@13.0.2(eslint@8.28.0)(typescript@4.9.3): - resolution: {integrity: sha512-SrrHp+zBDYLjOFZdM5b9aW/pliK687Xxfa+qpDuL08Z04ReHhmz3L+maXaAqgrEVZHQximP7nh0El4yNDJW+CA==} + /eslint-config-next@14.0.4(eslint@8.28.0)(typescript@4.9.3): + resolution: {integrity: sha512-9/xbOHEQOmQtqvQ1UsTQZpnA7SlDMBtuKJ//S4JnoyK3oGLhILKXdBgu/UO7lQo/2xOykQULS1qQ6p2+EpHgAQ==} peerDependencies: eslint: ^7.23.0 || ^8.0.0 typescript: '>=3.3.1' @@ -4912,15 +5133,15 @@ packages: typescript: optional: true dependencies: - '@next/eslint-plugin-next': 13.0.2 - '@rushstack/eslint-patch': 1.2.0 + '@next/eslint-plugin-next': 14.0.4 + '@rushstack/eslint-patch': 1.7.0 '@typescript-eslint/parser': 5.43.0(eslint@8.28.0)(typescript@4.9.3) eslint: 8.28.0 - eslint-import-resolver-node: 0.3.6 - eslint-import-resolver-typescript: 2.7.1(eslint-plugin-import@2.26.0)(eslint@8.28.0) - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-typescript@2.7.1)(eslint@8.28.0) - eslint-plugin-jsx-a11y: 6.6.1(eslint@8.28.0) - eslint-plugin-react: 7.31.11(eslint@8.28.0) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.28.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.28.0) + eslint-plugin-jsx-a11y: 6.8.0(eslint@8.28.0) + eslint-plugin-react: 7.33.2(eslint@8.28.0) eslint-plugin-react-hooks: 4.6.0(eslint@8.28.0) typescript: 4.9.3 transitivePeerDependencies: @@ -4928,35 +5149,41 @@ packages: - supports-color dev: true - /eslint-import-resolver-node@0.3.6: - resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==} + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} dependencies: debug: 3.2.7(supports-color@5.5.0) - resolve: 1.22.1 + is-core-module: 2.13.1 + resolve: 1.22.8 transitivePeerDependencies: - supports-color dev: true - /eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0)(eslint@8.28.0): - resolution: {integrity: sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==} - engines: {node: '>=4'} + /eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.28.0): + resolution: {integrity: sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==} + engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: eslint: '*' eslint-plugin-import: '*' dependencies: debug: 4.3.4 + enhanced-resolve: 5.15.0 eslint: 8.28.0 - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-typescript@2.7.1)(eslint@8.28.0) - glob: 7.2.3 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.28.0) + eslint-plugin-import: 2.29.1(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.28.0) + fast-glob: 3.3.2 + get-tsconfig: 4.7.2 + is-core-module: 2.13.1 is-glob: 4.0.3 - resolve: 1.22.1 - tsconfig-paths: 3.14.1 transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack - supports-color dev: true - /eslint-module-utils@2.7.4(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@2.7.1)(eslint@8.28.0): - resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} + /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.28.0): + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -4979,14 +5206,14 @@ packages: '@typescript-eslint/parser': 5.43.0(eslint@8.28.0)(typescript@4.9.3) debug: 3.2.7(supports-color@5.5.0) eslint: 8.28.0 - eslint-import-resolver-node: 0.3.6 - eslint-import-resolver-typescript: 2.7.1(eslint-plugin-import@2.26.0)(eslint@8.28.0) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1)(eslint@8.28.0) transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-typescript@2.7.1)(eslint@8.28.0): - resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} + /eslint-plugin-import@2.29.1(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.28.0): + resolution: {integrity: sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -4996,46 +5223,53 @@ packages: optional: true dependencies: '@typescript-eslint/parser': 5.43.0(eslint@8.28.0)(typescript@4.9.3) - array-includes: 3.1.6 - array.prototype.flat: 1.3.1 - debug: 2.6.9 + array-includes: 3.1.7 + array.prototype.findlastindex: 1.2.3 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7(supports-color@5.5.0) doctrine: 2.1.0 eslint: 8.28.0 - eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@2.7.1)(eslint@8.28.0) - has: 1.0.3 - is-core-module: 2.11.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.43.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.28.0) + hasown: 2.0.0 + is-core-module: 2.13.1 is-glob: 4.0.3 minimatch: 3.1.2 - object.values: 1.1.6 - resolve: 1.22.1 - tsconfig-paths: 3.14.1 + object.fromentries: 2.0.7 + object.groupby: 1.0.1 + object.values: 1.1.7 + semver: 6.3.1 + tsconfig-paths: 3.15.0 transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color dev: true - /eslint-plugin-jsx-a11y@6.6.1(eslint@8.28.0): - resolution: {integrity: sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==} + /eslint-plugin-jsx-a11y@6.8.0(eslint@8.28.0): + resolution: {integrity: sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==} engines: {node: '>=4.0'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - '@babel/runtime': 7.20.1 - aria-query: 4.2.2 - array-includes: 3.1.6 - ast-types-flow: 0.0.7 - axe-core: 4.5.2 - axobject-query: 2.2.0 + '@babel/runtime': 7.23.8 + aria-query: 5.3.0 + array-includes: 3.1.7 + array.prototype.flatmap: 1.3.2 + ast-types-flow: 0.0.8 + axe-core: 4.7.0 + axobject-query: 3.2.1 damerau-levenshtein: 1.0.8 emoji-regex: 9.2.2 + es-iterator-helpers: 1.0.15 eslint: 8.28.0 - has: 1.0.3 - jsx-ast-utils: 3.3.3 - language-tags: 1.0.5 + hasown: 2.0.0 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 minimatch: 3.1.2 - semver: 6.3.0 + object.entries: 1.1.7 + object.fromentries: 2.0.7 dev: true /eslint-plugin-react-hooks@4.6.0(eslint@8.28.0): @@ -5047,28 +5281,29 @@ packages: eslint: 8.28.0 dev: true - /eslint-plugin-react@7.31.11(eslint@8.28.0): - resolution: {integrity: sha512-TTvq5JsT5v56wPa9OYHzsrOlHzKZKjV+aLgS+55NJP/cuzdiQPC7PfYoUjMoxlffKtvijpk7vA/jmuqRb9nohw==} + /eslint-plugin-react@7.33.2(eslint@8.28.0): + resolution: {integrity: sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 dependencies: - array-includes: 3.1.6 - array.prototype.flatmap: 1.3.1 - array.prototype.tosorted: 1.1.1 + array-includes: 3.1.7 + array.prototype.flatmap: 1.3.2 + array.prototype.tosorted: 1.1.2 doctrine: 2.1.0 + es-iterator-helpers: 1.0.15 eslint: 8.28.0 estraverse: 5.3.0 - jsx-ast-utils: 3.3.3 + jsx-ast-utils: 3.3.5 minimatch: 3.1.2 - object.entries: 1.1.6 - object.fromentries: 2.0.6 - object.hasown: 1.1.2 - object.values: 1.1.6 + object.entries: 1.1.7 + object.fromentries: 2.0.7 + object.hasown: 1.1.3 + object.values: 1.1.7 prop-types: 15.8.1 - resolve: 2.0.0-next.4 - semver: 6.3.0 - string.prototype.matchall: 4.0.8 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.10 dev: true /eslint-scope@5.1.1: @@ -5284,6 +5519,17 @@ packages: merge2: 1.4.1 micromatch: 4.0.5 + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -5323,14 +5569,6 @@ packages: bser: 2.1.1 dev: true - /fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.2.1 - dev: false - /file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -5428,13 +5666,6 @@ packages: combined-stream: 1.0.8 mime-types: 2.1.35 - /formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} - dependencies: - fetch-blob: 3.2.0 - dev: false - /fraction.js@4.2.0: resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} dev: true @@ -5444,7 +5675,7 @@ packages: engines: {node: '>=10'} dependencies: at-least-node: 1.0.0 - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.0 @@ -5482,6 +5713,16 @@ packages: es-abstract: 1.20.4 functions-have-names: 1.2.3 + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + functions-have-names: 1.2.3 + dev: true + /functional-red-black-tree@1.0.1: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} requiresBuild: true @@ -5612,6 +5853,12 @@ packages: resolution: {integrity: sha512-X8u8fREiYOE6S8hLbq99PeykTDoLVnxvF4DjWKJmz9xy2nNRdUcV8ZN9tniJFeKyTU3qnC9lL8n4Chd6LmVKHg==} dev: true + /get-tsconfig@4.7.2: + resolution: {integrity: sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -5627,7 +5874,6 @@ packages: /glob-to-regexp@0.4.1: resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - dev: false /glob@10.3.10: resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} @@ -5686,6 +5932,13 @@ packages: type-fest: 0.20.2 dev: true + /globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + dev: true + /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -5790,9 +6043,6 @@ packages: dependencies: get-intrinsic: 1.2.2 - /graceful-fs@4.2.10: - resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} - /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -5830,6 +6080,12 @@ packages: dependencies: get-intrinsic: 1.1.3 + /has-property-descriptors@1.0.1: + resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + /has-proto@1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} engines: {node: '>= 0.4'} @@ -6028,6 +6284,13 @@ packages: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + /is-bigint@1.0.4: resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} dependencies: @@ -6060,6 +6323,12 @@ packages: dependencies: has: 1.0.3 + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + dev: true + /is-date-object@1.0.5: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} @@ -6075,6 +6344,12 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + /is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + dependencies: + call-bind: 1.0.5 + dev: true + /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} @@ -6085,6 +6360,13 @@ packages: engines: {node: '>=6'} dev: true + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.0 + dev: true + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -6285,6 +6567,16 @@ packages: istanbul-lib-report: 3.0.1 dev: true + /iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.4 + set-function-name: 2.0.1 + dev: true + /jackspeak@2.3.6: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} engines: {node: '>=14'} @@ -6755,8 +7047,8 @@ packages: - ts-node dev: true - /jose@4.11.0: - resolution: {integrity: sha512-wLe+lJHeG8Xt6uEubS4x0LVjS/3kXXu9dGoj9BNnlhYq7Kts0Pbb2pvv5KiI0yaKH/eaiR0LUOBhOVo9ktd05A==} + /jose@4.15.4: + resolution: {integrity: sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==} dev: false /js-beautify@1.14.11: @@ -6947,11 +7239,11 @@ packages: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true - /json5@1.0.1: - resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} + /json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true dependencies: - minimist: 1.2.7 + minimist: 1.2.8 dev: true /json5@2.2.3: @@ -6980,12 +7272,14 @@ packages: semver: 7.5.4 dev: false - /jsx-ast-utils@3.3.3: - resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==} + /jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} engines: {node: '>=4.0'} dependencies: - array-includes: 3.1.6 - object.assign: 4.1.4 + array-includes: 3.1.7 + array.prototype.flat: 1.3.2 + object.assign: 4.1.5 + object.values: 1.1.7 dev: true /jwa@1.4.1: @@ -7013,7 +7307,7 @@ packages: '@types/express': 4.17.16 '@types/jsonwebtoken': 9.0.1 debug: 4.3.4 - jose: 4.11.0 + jose: 4.15.4 limiter: 1.1.5 lru-memoizer: 2.1.4 transitivePeerDependencies: @@ -7060,8 +7354,9 @@ packages: resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} dev: true - /language-tags@1.0.5: - resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==} + /language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} dependencies: language-subtag-registry: 0.3.22 dev: true @@ -7115,7 +7410,7 @@ packages: resolution: {integrity: sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==} engines: {node: '>=4'} dependencies: - graceful-fs: 4.2.10 + graceful-fs: 4.2.11 parse-json: 4.0.0 pify: 3.0.0 strip-bom: 3.0.0 @@ -7373,8 +7668,6 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} requiresBuild: true - dev: false - optional: true /minipass@3.3.4: resolution: {integrity: sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==} @@ -7408,10 +7701,6 @@ packages: dev: false optional: true - /ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: true - /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -7428,6 +7717,12 @@ packages: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + dev: true + + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true /natural-compare-lite@1.4.0: resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} @@ -7441,11 +7736,10 @@ packages: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} dev: false - /next-auth@4.15.1(next@13.0.2)(nodemailer@6.9.7)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-yB/cSEqslaXAsLZ3lvkJbB7bRR5JeZvfUXSw0CmWeP+TaMZWB85fG9PWdfBeFrDCLBsoyATw9FF6fzApE0SxSw==} - engines: {node: ^12.19.0 || ^14.15.0 || ^16.13.0 || ^18.12.0} + /next-auth@4.24.5(next@14.0.4)(nodemailer@6.9.7)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-3RafV3XbfIKk6rF6GlLE4/KxjTcuMCifqrmD+98ejFq73SRoj2rmzoca8u764977lH/Q7jo6Xu6yM+Re1Mz/Og==} peerDependencies: - next: ^12.2.5 || ^13 + next: ^12.2.5 || ^13 || ^14 nodemailer: ^6.6.5 react: ^17.0.2 || ^18 react-dom: ^17.0.2 || ^18 @@ -7453,30 +7747,30 @@ packages: nodemailer: optional: true dependencies: - '@babel/runtime': 7.20.1 - '@panva/hkdf': 1.0.2 + '@babel/runtime': 7.23.8 + '@panva/hkdf': 1.1.1 cookie: 0.5.0 - jose: 4.11.0 - next: 13.0.2(@babel/core@7.23.6)(react-dom@18.2.0)(react@18.2.0) + jose: 4.15.4 + next: 14.0.4(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0) nodemailer: 6.9.7 oauth: 0.9.15 - openid-client: 5.3.0 - preact: 10.11.3 - preact-render-to-string: 5.2.6(preact@10.11.3) + openid-client: 5.6.4 + preact: 10.19.3 + preact-render-to-string: 5.2.6(preact@10.19.3) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) uuid: 8.3.2 dev: false - /next-pwa@5.6.0(@babel/core@7.23.6)(next@13.0.2)(webpack@5.89.0): + /next-pwa@5.6.0(@babel/core@7.23.7)(next@14.0.4)(webpack@5.89.0): resolution: {integrity: sha512-XV8g8C6B7UmViXU8askMEYhWwQ4qc/XqJGnexbLV68hzKaGHZDMtHsm2TNxFcbR7+ypVuth/wwpiIlMwpRJJ5A==} peerDependencies: next: '>=9.0.0' dependencies: - babel-loader: 8.3.0(@babel/core@7.23.6)(webpack@5.89.0) + babel-loader: 8.3.0(@babel/core@7.23.7)(webpack@5.89.0) clean-webpack-plugin: 4.0.0(webpack@5.89.0) globby: 11.1.0 - next: 13.0.2(@babel/core@7.23.6)(react-dom@18.2.0)(react@18.2.0) + next: 14.0.4(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0) terser-webpack-plugin: 5.3.6(webpack@5.89.0) workbox-webpack-plugin: 6.5.4(webpack@5.89.0) workbox-window: 6.5.4 @@ -7490,7 +7784,7 @@ packages: - webpack dev: false - /next-superjson@0.0.4(next@13.0.2)(superjson@1.9.1)(webpack@5.89.0): + /next-superjson@0.0.4(next@14.0.4)(superjson@1.9.1)(webpack@5.89.0): resolution: {integrity: sha512-PYtoHbPcZYED8Vm9YCIQIZi/arANNnf6grwjkPuJXzWdY1TxJxrn9dCPmVj6ALvPn9YcDThwEA9WvHq/NyzMvw==} peerDependencies: next: '>=10' @@ -7499,67 +7793,97 @@ packages: '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.20.12) '@babel/plugin-syntax-typescript': 7.20.0(@babel/core@7.20.12) babel-loader: 8.3.0(@babel/core@7.20.12)(webpack@5.89.0) - babel-plugin-superjson-next: 0.4.5(next@13.0.2)(superjson@1.9.1) - next: 13.0.2(@babel/core@7.23.6)(react-dom@18.2.0)(react@18.2.0) + babel-plugin-superjson-next: 0.4.5(next@14.0.4)(superjson@1.9.1) + next: 14.0.4(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0) transitivePeerDependencies: - superjson - supports-color - webpack dev: false - /next@13.0.2(@babel/core@7.23.6)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-uQ5z5e4D9mOe8+upy6bQdYYjo/kk1v3jMW87kTy2TgAyAsEO+CkwRnMgyZ4JoHEnhPZLHwh7dk0XymRNLe1gFw==} - engines: {node: '>=14.6.0'} + /next@13.5.6(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Y2wTcTbO4WwEsVb4A8VSnOsG1I9ok+h74q0ZdxkwM3EODqrs4pasq7O0iUxbcS9VtWMicG7f3+HAj0r1+NtKSw==} + engines: {node: '>=16.14.0'} hasBin: true peerDependencies: - fibers: '>= 3.1.0' - node-sass: ^6.0.0 || ^7.0.0 + '@opentelemetry/api': ^1.1.0 react: ^18.2.0 react-dom: ^18.2.0 sass: ^1.3.0 peerDependenciesMeta: - fibers: - optional: true - node-sass: + '@opentelemetry/api': optional: true sass: optional: true dependencies: - '@next/env': 13.0.2 - '@swc/helpers': 0.4.11 + '@next/env': 13.5.6 + '@swc/helpers': 0.5.2 + busboy: 1.6.0 caniuse-lite: 1.0.30001568 - postcss: 8.4.14 + postcss: 8.4.31 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) - styled-jsx: 5.1.0(@babel/core@7.23.6)(react@18.2.0) - use-sync-external-store: 1.2.0(react@18.2.0) + styled-jsx: 5.1.1(@babel/core@7.23.7)(react@18.2.0) + watchpack: 2.4.0 optionalDependencies: - '@next/swc-android-arm-eabi': 13.0.2 - '@next/swc-android-arm64': 13.0.2 - '@next/swc-darwin-arm64': 13.0.2 - '@next/swc-darwin-x64': 13.0.2 - '@next/swc-freebsd-x64': 13.0.2 - '@next/swc-linux-arm-gnueabihf': 13.0.2 - '@next/swc-linux-arm64-gnu': 13.0.2 - '@next/swc-linux-arm64-musl': 13.0.2 - '@next/swc-linux-x64-gnu': 13.0.2 - '@next/swc-linux-x64-musl': 13.0.2 - '@next/swc-win32-arm64-msvc': 13.0.2 - '@next/swc-win32-ia32-msvc': 13.0.2 - '@next/swc-win32-x64-msvc': 13.0.2 + '@next/swc-darwin-arm64': 13.5.6 + '@next/swc-darwin-x64': 13.5.6 + '@next/swc-linux-arm64-gnu': 13.5.6 + '@next/swc-linux-arm64-musl': 13.5.6 + '@next/swc-linux-x64-gnu': 13.5.6 + '@next/swc-linux-x64-musl': 13.5.6 + '@next/swc-win32-arm64-msvc': 13.5.6 + '@next/swc-win32-ia32-msvc': 13.5.6 + '@next/swc-win32-x64-msvc': 13.5.6 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros + dev: true + + /next@14.0.4(@babel/core@7.23.7)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-qbwypnM7327SadwFtxXnQdGiKpkuhaRLE2uq62/nRul9cj9KhQ5LhHmlziTNqUidZotw/Q1I9OjirBROdUJNgA==} + engines: {node: '>=18.17.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + react: ^18.2.0 + react-dom: ^18.2.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + sass: + optional: true + dependencies: + '@next/env': 14.0.4 + '@swc/helpers': 0.5.2 + busboy: 1.6.0 + caniuse-lite: 1.0.30001578 + graceful-fs: 4.2.11 + postcss: 8.4.31 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + styled-jsx: 5.1.1(@babel/core@7.23.7)(react@18.2.0) + watchpack: 2.4.0 + optionalDependencies: + '@next/swc-darwin-arm64': 14.0.4 + '@next/swc-darwin-x64': 14.0.4 + '@next/swc-linux-arm64-gnu': 14.0.4 + '@next/swc-linux-arm64-musl': 14.0.4 + '@next/swc-linux-x64-gnu': 14.0.4 + '@next/swc-linux-x64-musl': 14.0.4 + '@next/swc-win32-arm64-msvc': 14.0.4 + '@next/swc-win32-ia32-msvc': 14.0.4 + '@next/swc-win32-x64-msvc': 14.0.4 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + dev: false /nice-try@1.0.5: resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==} dev: true - /node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - dev: false - /node-fetch@2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} engines: {node: 4.x || >=6.0.0} @@ -7588,15 +7912,6 @@ packages: dev: false optional: true - /node-fetch@3.3.0: - resolution: {integrity: sha512-BKwRP/O0UvoMKp7GNdwPlObhYGB5DQqwhEDQlNKuoqwVYSxkSZCSbHjnFFmUEtwSKRPU4kNK8PbDYYitwaE3QA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - data-uri-to-buffer: 4.0.0 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - dev: false - /node-forge@1.3.1: resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} engines: {node: '>= 6.13.0'} @@ -7740,6 +8055,10 @@ packages: /object-inspect@1.12.2: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + /object-is@1.1.5: resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==} engines: {node: '>= 0.4'} @@ -7761,42 +8080,61 @@ packages: has-symbols: 1.0.3 object-keys: 1.1.1 - /object.entries@1.1.6: - resolution: {integrity: sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==} + /object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 + call-bind: 1.0.5 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 dev: true - /object.fromentries@2.0.6: - resolution: {integrity: sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==} + /object.entries@1.1.7: + resolution: {integrity: sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 dev: true - /object.hasown@1.1.2: - resolution: {integrity: sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==} + /object.fromentries@2.0.7: + resolution: {integrity: sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==} + engines: {node: '>= 0.4'} dependencies: - define-properties: 1.1.4 - es-abstract: 1.20.4 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 dev: true - /object.values@1.1.6: - resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} + /object.groupby@1.0.1: + resolution: {integrity: sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + dev: true + + /object.hasown@1.1.3: + resolution: {integrity: sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + + /object.values@1.1.7: + resolution: {integrity: sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==} engines: {node: '>= 0.4'} dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.4 + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 dev: true - /oidc-token-hash@5.0.1: - resolution: {integrity: sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==} + /oidc-token-hash@5.0.3: + resolution: {integrity: sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==} engines: {node: ^10.13.0 || >=12.0.0} dev: false @@ -7812,13 +8150,13 @@ packages: mimic-fn: 2.1.0 dev: true - /openid-client@5.3.0: - resolution: {integrity: sha512-SykPCeZBZ/SxiBH5AWynvFUIDX3//2pgwc/3265alUmGHeCN03+X8uP+pHOVnCXCKfX/XOhO90qttAQ76XcGxA==} + /openid-client@5.6.4: + resolution: {integrity: sha512-T1h3B10BRPKfcObdBklX639tVz+xh34O7GjofqrqiAQdm7eHsQ00ih18x6wuJ/E6FxdtS2u3FmUGPDeEcMwzNA==} dependencies: - jose: 4.11.0 + jose: 4.15.4 lru-cache: 6.0.0 object-hash: 2.2.0 - oidc-token-hash: 5.0.1 + oidc-token-hash: 5.0.3 dev: false /optionator@0.8.3: @@ -8082,34 +8420,34 @@ packages: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} dev: true - /postcss@8.4.14: - resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} + /postcss@8.4.19: + resolution: {integrity: sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==} engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.4 picocolors: 1.0.0 source-map-js: 1.0.2 + dev: true - /postcss@8.4.19: - resolution: {integrity: sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==} + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.3.4 + nanoid: 3.3.7 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: true - /preact-render-to-string@5.2.6(preact@10.11.3): + /preact-render-to-string@5.2.6(preact@10.19.3): resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==} peerDependencies: preact: '>=10' dependencies: - preact: 10.11.3 + preact: 10.19.3 pretty-format: 3.8.0 dev: false - /preact@10.11.3: - resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==} + /preact@10.19.3: + resolution: {integrity: sha512-nHHTeFVBTHRGxJXKkKu5hT8C/YWBkPso4/Gad6xuj5dbptt9iF9NZr9pHbPhBrnT2klheu7mHTxTZ/LjwJiEiQ==} dev: false /prelude-ls@1.1.2: @@ -8404,6 +8742,18 @@ packages: strip-indent: 3.0.0 dev: true + /reflect.getprototypeof@1.0.4: + resolution: {integrity: sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + globalthis: 1.0.3 + which-builtin-type: 1.1.3 + dev: true + /regenerate-unicode-properties@10.1.0: resolution: {integrity: sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==} engines: {node: '>=4'} @@ -8416,6 +8766,9 @@ packages: /regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + /regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + /regenerator-transform@0.15.1: resolution: {integrity: sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==} dependencies: @@ -8505,6 +8858,10 @@ packages: engines: {node: '>=8'} dev: true + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true + /resolve.exports@2.0.2: resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} engines: {node: '>=10'} @@ -8518,11 +8875,20 @@ packages: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - /resolve@2.0.0-next.4: - resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true dependencies: - is-core-module: 2.11.0 + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + dependencies: + is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 dev: true @@ -8587,6 +8953,16 @@ packages: dependencies: queue-microtask: 1.2.3 + /safe-array-concat@1.1.0: + resolution: {integrity: sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: true + /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -8597,6 +8973,15 @@ packages: get-intrinsic: 1.1.3 is-regex: 1.1.4 + /safe-regex-test@1.0.2: + resolution: {integrity: sha512-83S9w6eFq12BBIJYvjMux6/dkirb8+4zJRA9cxNBVb7Wq5fJBW+Xze48WqR8pxua7bDuAaaAxtVVd4Idjp1dBQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-regex: 1.1.4 + dev: true + /safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} requiresBuild: true @@ -8699,6 +9084,12 @@ packages: randombytes: 2.1.0 dev: false + /serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + dependencies: + randombytes: 2.1.0 + dev: false + /set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} requiresBuild: true @@ -8886,6 +9277,10 @@ packages: dev: false optional: true + /streamsearch@1.1.0: + resolution: {integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==} + engines: {node: '>=10.0.0'} + /string-length@4.0.2: resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} engines: {node: '>=10'} @@ -8912,6 +9307,20 @@ packages: strip-ansi: 7.1.0 dev: false + /string.prototype.matchall@4.0.10: + resolution: {integrity: sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + get-intrinsic: 1.2.2 + has-symbols: 1.0.3 + internal-slot: 1.0.6 + regexp.prototype.flags: 1.5.1 + set-function-name: 2.0.1 + side-channel: 1.0.4 + dev: true + /string.prototype.matchall@4.0.8: resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==} dependencies: @@ -8933,6 +9342,15 @@ packages: es-abstract: 1.20.4 dev: true + /string.prototype.trim@1.2.8: + resolution: {integrity: sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + /string.prototype.trimend@1.0.6: resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} dependencies: @@ -8940,6 +9358,14 @@ packages: define-properties: 1.1.4 es-abstract: 1.20.4 + /string.prototype.trimend@1.0.7: + resolution: {integrity: sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + /string.prototype.trimstart@1.0.6: resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} dependencies: @@ -8947,6 +9373,14 @@ packages: define-properties: 1.1.4 es-abstract: 1.20.4 + /string.prototype.trimstart@1.0.7: + resolution: {integrity: sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==} + dependencies: + call-bind: 1.0.5 + define-properties: 1.2.1 + es-abstract: 1.22.3 + dev: true + /string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} requiresBuild: true @@ -9018,8 +9452,8 @@ packages: dev: false optional: true - /styled-jsx@5.1.0(@babel/core@7.23.6)(react@18.2.0): - resolution: {integrity: sha512-/iHaRJt9U7T+5tp6TRelLnqBqiaIT0HsO0+vgyj8hK2KUk7aejFqRrumqPUlAqDwAj8IbS/1hk3IhBAAK/FCUQ==} + /styled-jsx@5.1.1(@babel/core@7.23.7)(react@18.2.0): + resolution: {integrity: sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==} engines: {node: '>= 12.0.0'} peerDependencies: '@babel/core': '*' @@ -9031,7 +9465,7 @@ packages: babel-plugin-macros: optional: true dependencies: - '@babel/core': 7.23.6 + '@babel/core': 7.23.7 client-only: 0.0.1 react: 18.2.0 @@ -9105,7 +9539,6 @@ packages: /tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} - dev: false /tar@6.1.12: resolution: {integrity: sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw==} @@ -9150,8 +9583,8 @@ packages: type-fest: 0.16.0 unique-string: 2.0.0 - /terser-webpack-plugin@5.3.6(webpack@5.89.0): - resolution: {integrity: sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==} + /terser-webpack-plugin@5.3.10(webpack@5.89.0): + resolution: {integrity: sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==} engines: {node: '>= 10.13.0'} peerDependencies: '@swc/core': '*' @@ -9166,16 +9599,16 @@ packages: uglify-js: optional: true dependencies: - '@jridgewell/trace-mapping': 0.3.17 + '@jridgewell/trace-mapping': 0.3.21 jest-worker: 27.5.1 - schema-utils: 3.1.1 - serialize-javascript: 6.0.1 - terser: 5.16.4 + schema-utils: 3.3.0 + serialize-javascript: 6.0.2 + terser: 5.27.0 webpack: 5.89.0 dev: false - /terser-webpack-plugin@5.3.9(webpack@5.89.0): - resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==} + /terser-webpack-plugin@5.3.6(webpack@5.89.0): + resolution: {integrity: sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==} engines: {node: '>= 10.13.0'} peerDependencies: '@swc/core': '*' @@ -9190,11 +9623,11 @@ packages: uglify-js: optional: true dependencies: - '@jridgewell/trace-mapping': 0.3.20 + '@jridgewell/trace-mapping': 0.3.17 jest-worker: 27.5.1 - schema-utils: 3.3.0 + schema-utils: 3.1.1 serialize-javascript: 6.0.1 - terser: 5.26.0 + terser: 5.16.4 webpack: 5.89.0 dev: false @@ -9208,13 +9641,13 @@ packages: commander: 2.20.3 source-map-support: 0.5.21 - /terser@5.26.0: - resolution: {integrity: sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==} + /terser@5.27.0: + resolution: {integrity: sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==} engines: {node: '>=10'} hasBin: true dependencies: '@jridgewell/source-map': 0.3.5 - acorn: 8.11.2 + acorn: 8.11.3 commander: 2.20.3 source-map-support: 0.5.21 dev: false @@ -9325,12 +9758,12 @@ packages: yn: 3.1.1 dev: true - /tsconfig-paths@3.14.1: - resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} dependencies: '@types/json5': 0.0.29 - json5: 1.0.1 - minimist: 1.2.7 + json5: 1.0.2 + minimist: 1.2.8 strip-bom: 3.0.0 dev: true @@ -9340,6 +9773,10 @@ packages: /tslib@2.4.1: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} + dev: false + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} /tsutils@3.21.0(typescript@4.9.3): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} @@ -9395,6 +9832,44 @@ packages: engines: {node: '>=10'} dev: true + /typed-array-buffer@1.0.0: + resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-length@1.0.0: + resolution: {integrity: sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-byte-offset@1.0.0: + resolution: {integrity: sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.5 + call-bind: 1.0.5 + for-each: 0.3.3 + has-proto: 1.0.1 + is-typed-array: 1.1.12 + dev: true + + /typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + dependencies: + call-bind: 1.0.5 + for-each: 0.3.3 + is-typed-array: 1.1.12 + dev: true + /typescript@4.9.3: resolution: {integrity: sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==} engines: {node: '>=4.2.0'} @@ -9520,6 +9995,7 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 dependencies: react: 18.2.0 + dev: false /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -9603,12 +10079,6 @@ packages: dependencies: glob-to-regexp: 0.4.1 graceful-fs: 4.2.11 - dev: false - - /web-streams-polyfill@3.2.1: - resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} - engines: {node: '>= 8'} - dev: false /webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -9651,8 +10121,8 @@ packages: '@webassemblyjs/ast': 1.11.6 '@webassemblyjs/wasm-edit': 1.11.6 '@webassemblyjs/wasm-parser': 1.11.6 - acorn: 8.11.2 - acorn-import-assertions: 1.9.0(acorn@8.11.2) + acorn: 8.11.3 + acorn-import-assertions: 1.9.0(acorn@8.11.3) browserslist: 4.22.2 chrome-trace-event: 1.0.3 enhanced-resolve: 5.15.0 @@ -9667,7 +10137,7 @@ packages: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.9(webpack@5.89.0) + terser-webpack-plugin: 5.3.10(webpack@5.89.0) watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -9745,6 +10215,24 @@ packages: is-string: 1.0.7 is-symbol: 1.0.4 + /which-builtin-type@1.1.3: + resolution: {integrity: sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==} + engines: {node: '>= 0.4'} + dependencies: + function.prototype.name: 1.1.6 + has-tostringtag: 1.0.0 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.1 + which-typed-array: 1.1.13 + dev: true + /which-collection@1.0.1: resolution: {integrity: sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==} dependencies: @@ -10049,8 +10537,8 @@ packages: engines: {node: '>=10'} requiresBuild: true - /zod@3.20.2: - resolution: {integrity: sha512-1MzNQdAvO+54H+EaK5YpyEy0T+Ejo/7YLHS93G3RnYWh5gaotGHwGeN/ZO687qEDU2y4CdStQYXVHIgrUl5UVQ==} + /zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} dev: false /zustand@4.3.2(react@18.2.0): diff --git a/src/components/draw/DrawingArea.tsx b/src/components/draw/DrawingArea.tsx index 1c1854d..6600c3e 100644 --- a/src/components/draw/DrawingArea.tsx +++ b/src/components/draw/DrawingArea.tsx @@ -74,15 +74,11 @@ const DrawingArea: React.FC = ({ onSave }) => { const observer = useRef( new ResizeObserver((entries) => { - if (!entries) { + if (!entries || !entries.length || !entries[0]?.contentRect) { return; } - if (entries.length === 0) { - return; - } - - setDrawAreaHeight(entries[0]!.contentRect.height - margin); + setDrawAreaHeight(entries[0].contentRect.height - margin); }) ); diff --git a/src/components/ui/modal/Modal.tsx b/src/components/ui/modal/Modal.tsx index 1ba6013..afa6f81 100644 --- a/src/components/ui/modal/Modal.tsx +++ b/src/components/ui/modal/Modal.tsx @@ -1,11 +1,5 @@ -import type { - PropsWithChildren} from "react"; -import { - cloneElement, - Fragment, - useEffect, - useState, -} from "react"; +import type { PropsWithChildren } from "react"; +import { cloneElement, Fragment, useEffect } from "react"; import { Dialog, Transition } from "@headlessui/react"; import { create } from "zustand"; import Btn from "../Btn"; @@ -23,6 +17,7 @@ export const useModalStore = create((set) => ({ })); export interface BaseModalProps { + // eslint-disable-next-line close?: (value: any) => void; state?: ModalState; } diff --git a/src/models/draw_event.model.ts b/src/models/draw_event.model.ts index d2c7322..120906f 100644 --- a/src/models/draw_event.model.ts +++ b/src/models/draw_event.model.ts @@ -1,4 +1,7 @@ -import type { ImageEvent, ImageEventWithSender } from "../server/domain/db/client"; +import type { + ImageEvent, + ImageEventWithSender, +} from "../server/domain/db/client"; export default class BaseDrawEvent { constructor(data: ImageEvent) { @@ -18,7 +21,7 @@ export default class BaseDrawEvent { } export class NotificationDrawEvent extends BaseDrawEvent { - constructor(data: any); + constructor(data: unknown); constructor(data: ImageEventWithSender) { super(data); diff --git a/src/pages/add_a_friend.tsx b/src/pages/add_a_friend.tsx index f269099..572997e 100644 --- a/src/pages/add_a_friend.tsx +++ b/src/pages/add_a_friend.tsx @@ -11,7 +11,7 @@ import { Routes } from "../enums/routes.enum"; import AuthAppShell from "../layout/AuthAppShell"; import { createContext } from "../server/trpc/context"; import { trpc } from "../utils/trpc"; -import { Friend } from "../server/domain/db/client"; +import { type Friend } from "../server/domain/db/client"; export async function getServerSideProps(context: CreateNextContextOptions) { const ctx = await createContext(context); diff --git a/src/pages/api/auth/[...nextauth].ts b/src/pages/api/auth/[...nextauth].ts index 965d929..d5b3a50 100644 --- a/src/pages/api/auth/[...nextauth].ts +++ b/src/pages/api/auth/[...nextauth].ts @@ -24,7 +24,6 @@ export const authOptions: NextAuthOptions = { EmailProvider({ from: env.EMAIL_FROM, maxAge: 5 * 60, - name: "email", async generateVerificationToken() { // TODO: This isn't crypto safe. Needs updating return [...Array(6)].map(() => (Math.random() * 10) | 0).join(``); diff --git a/src/pages/draw.tsx b/src/pages/draw.tsx index 49a0813..286ea06 100644 --- a/src/pages/draw.tsx +++ b/src/pages/draw.tsx @@ -13,7 +13,7 @@ import { useModal } from "../components/ui/modal/Modal"; import type { User } from "@prisma/client"; import Icon from "../components/ui/Icon"; import AuthAppShell from "../layout/AuthAppShell"; -import { Friend } from "../server/domain/db/client"; +import { type Friend } from "../server/domain/db/client"; const DrawingArea = dynamic(() => import("../components/draw/DrawingArea"), { ssr: false, @@ -98,12 +98,12 @@ const Draw: NextPage = () => { ); const onSave = async (image: string) => { - if (!data || !data.length) { + if (!data || !data.length || !data[0]?.id) { return; } try { - let selectedFriendId = data[0]!.id; + let selectedFriendId = data[0].id; if (data.length > 1) { const selectedFriend = await show(); if (!selectedFriend) { diff --git a/src/pages/new_user.tsx b/src/pages/new_user.tsx index 1e7f32a..19e291f 100644 --- a/src/pages/new_user.tsx +++ b/src/pages/new_user.tsx @@ -1,4 +1,3 @@ -import { useAutoAnimate } from "@formkit/auto-animate/react"; import type { CreateNextContextOptions } from "@trpc/server/adapters/next"; import type { NextPage, InferGetServerSidePropsType } from "next"; import { useRouter } from "next/router"; diff --git a/src/pages/sign_in.tsx b/src/pages/sign_in.tsx index 0ddb1db..d58d27f 100644 --- a/src/pages/sign_in.tsx +++ b/src/pages/sign_in.tsx @@ -32,17 +32,19 @@ export async function getServerSideProps(context: CtxOrReq | undefined) { const csrfToken = await getCsrfToken(context); return { - props: { providers, csrfToken, host: context?.req?.headers.host }, + props: { providers, csrfToken, host: context?.req?.headers?.host }, }; } const SignIn: NextPage< InferGetServerSidePropsType > = ({ providers, csrfToken, host }) => { + const title = `${AppConstants.appTitle} | Sign In`; + return ( - {AppConstants.appTitle} | Sign In + {title}
diff --git a/src/pages/sign_out.tsx b/src/pages/sign_out.tsx index 28319ee..b0e42e4 100644 --- a/src/pages/sign_out.tsx +++ b/src/pages/sign_out.tsx @@ -11,8 +11,8 @@ const SignOut: NextPage = () => { const router = useRouter(); useEffect(() => { - signOut().then(() => { - router.replace(Routes.SignIn); + signOut({ redirect: false, callbackUrl: Routes.SignIn }).then((data) => { + router.replace(data.url); }); }, []); diff --git a/src/server/provider/global-ref.ts b/src/server/provider/global-ref.ts index 53177e8..3131af0 100644 --- a/src/server/provider/global-ref.ts +++ b/src/server/provider/global-ref.ts @@ -16,6 +16,7 @@ export default class GlobalRef { * Gets the value. */ get value() { + // eslint-disable-next-line return (global as any)[this.sym] as T; } @@ -23,6 +24,7 @@ export default class GlobalRef { * Sets the value. */ set value(value: T) { + // eslint-disable-next-line (global as any)[this.sym] = value; } } diff --git a/src/server/services/user.service.ts b/src/server/services/user.service.ts index dd1df73..7a18441 100644 --- a/src/server/services/user.service.ts +++ b/src/server/services/user.service.ts @@ -1,4 +1,4 @@ -import { Friend, User, type IUserDomain } from "../domain/db/client"; +import { type Friend, type User, type IUserDomain } from "../domain/db/client"; import NotFoundError from "./errors/not-found.error"; import ValidationError from "./errors/validation.error"; import { exclude } from "../../utils/helper.utils"; diff --git a/src/server/wss-dev-server.ts b/src/server/wss-dev-server.ts index d1a0ac8..63364b2 100644 --- a/src/server/wss-dev-server.ts +++ b/src/server/wss-dev-server.ts @@ -1,6 +1,5 @@ import { applyWSSHandler } from "@trpc/server/adapters/ws"; import ws from "ws"; -import fetch from "node-fetch"; import { appRouter } from "./trpc/router/_app"; import { createContext } from "./trpc/context"; import { env } from "../env/server"; @@ -9,10 +8,6 @@ import { env } from "../env/server"; * This file is used to run a WebSocket server for development purposes only. */ -if (!global.fetch) { - (global as any).fetch = fetch; -} - const wssDevLog = (msg: string) => { console.log(`[Dev WSS] ${msg}`); }; From 4927b427d708d08c9acfa08aeb29518a6ab24b03 Mon Sep 17 00:00:00 2001 From: Nick Leslie Date: Sun, 21 Jan 2024 18:34:55 -0500 Subject: [PATCH 2/3] Added base for anon sign in --- src/env/schema.js | 14 +++--- src/pages/api/auth/[...nextauth].ts | 77 +++++++++++++++++++++++++++-- src/pages/sign_in.tsx | 44 ++++++++++++++++- src/server/trpc/context.ts | 1 + 4 files changed, 125 insertions(+), 11 deletions(-) diff --git a/src/env/schema.js b/src/env/schema.js index 169cf04..05c3a44 100644 --- a/src/env/schema.js +++ b/src/env/schema.js @@ -16,13 +16,13 @@ export const serverSchema = z.object({ process.env.NODE_ENV === "production" ? z.string().min(1) : z.string().min(1).optional(), - NEXTAUTH_URL: z.preprocess( - // This makes Vercel deployments not fail if you don't set NEXTAUTH_URL - // Since NextAuth automatically uses the VERCEL_URL if present. - (str) => process.env.VERCEL_URL ?? str, - // VERCEL_URL doesnt include `https` so it cant be validated as a URL - process.env.VERCEL ? z.string() : z.string().url() - ), + // NEXTAUTH_URL: z.preprocess( + // // This makes Vercel deployments not fail if you don't set NEXTAUTH_URL + // // Since NextAuth automatically uses the VERCEL_URL if present. + // (str) => process.env.VERCEL_URL ?? str, + // // VERCEL_URL doesnt include `https` so it cant be validated as a URL + // process.env.VERCEL ? z.string() : z.string().url() + // ), // Email Processing EMAIL_FROM: z.string(), diff --git a/src/pages/api/auth/[...nextauth].ts b/src/pages/api/auth/[...nextauth].ts index d5b3a50..a6a358d 100644 --- a/src/pages/api/auth/[...nextauth].ts +++ b/src/pages/api/auth/[...nextauth].ts @@ -1,18 +1,63 @@ -import type { Theme } from "next-auth"; +import type { Account, Profile, Session, Theme, User } from "next-auth"; import NextAuth, { type NextAuthOptions } from "next-auth"; import EmailProvider from "next-auth/providers/email"; +import CredentialsProvider from "next-auth/providers/credentials"; import { PrismaAdapter } from "@next-auth/prisma-adapter"; import { Routes } from "../../../enums/routes.enum"; import { prisma } from "../../../server/domain/db/client"; import { env } from "../../../env/server"; import { Resend } from "resend"; import AppConstants from "../../../constants/app.constants"; +import { AdapterUser } from "next-auth/adapters"; +import { JWT } from "next-auth/jwt"; +import { connect } from "http2"; export const authOptions: NextAuthOptions = { callbacks: { - session({ session, user }) { + async jwt({ + token, + account, + profile, + }: { + token: JWT; + account: Account | null; + profile?: Profile; + }): Promise { + if (!token.provider) { + token.provider = "anonymous"; + } + return token; + }, + async session({ + session, + token, + user, + }: { + session: Session & { token_provider?: {} }; + token: JWT; + user?: AdapterUser; + }): Promise { + console.log("session", session); + console.log("user", user); + console.log("token", token); + let sessionUser = user; + + if (!sessionUser && session.user?.email) { + sessionUser = (await prisma.user.findUnique({ + where: { + email: session.user.email, + }, + })) as AdapterUser; + } + if (session.user) { - session.user["id"] = user.id; + // TODO: Fix this + session.user["id"] = user?.id || sessionUser?.id || ""; + } + + // don't make the token (JWT) contents available to the client session (JWT), but flag that they're server-side + if (token.provider) { + session.token_provider = token.provider; } return session; }, @@ -40,7 +85,17 @@ export const authOptions: NextAuthOptions = { }); }, }), + CredentialsProvider({ + name: "anonymous", + credentials: {}, + async authorize(credentials, req) { + return createAnonymousUser(); + }, + }), ], + session: { + strategy: "jwt", + }, pages: { signIn: Routes.SignIn, newUser: Routes.NewUser, @@ -110,3 +165,19 @@ function html(params: { `; } + +const createAnonymousUser = async () => { + // generate a random name and email for this anonymous user + const id = [...Array(6)].map(() => (Math.random() * 10) | 0).join(``); + const user = await prisma.user.create({ + data: { + id: id, + email: `guest-${id}@guest.com`, + emailVerified: new Date(), + }, + }); + + console.log("user", user); + + return user; +}; diff --git a/src/pages/sign_in.tsx b/src/pages/sign_in.tsx index d58d27f..b22e96a 100644 --- a/src/pages/sign_in.tsx +++ b/src/pages/sign_in.tsx @@ -5,9 +5,10 @@ import { signIn, getCsrfToken, getSession, + useSession, } from "next-auth/react"; import Head from "next/head"; -import React, { useState } from "react"; +import React, { FormEvent, useEffect, useState } from "react"; import EmailLogin from "../components/signin/EmailLogin"; import { VerificationStep } from "../components/signin/VerificationStep"; import { Routes } from "../enums/routes.enum"; @@ -15,6 +16,9 @@ import UnauthAppShell from "../layout/UnauthAppShell"; import type EmailSignUpFormData from "../models/email-signup-form-data.model"; import Icon from "../components/ui/Icon"; import AppConstants from "../constants/app.constants"; +import Btn from "../components/ui/Btn"; +import { router } from "../server/trpc/trpc"; +import { useRouter } from "next/router"; export async function getServerSideProps(context: CtxOrReq | undefined) { const session = await getSession(context); @@ -40,6 +44,25 @@ const SignIn: NextPage< InferGetServerSidePropsType > = ({ providers, csrfToken, host }) => { const title = `${AppConstants.appTitle} | Sign In`; + const router = useRouter(); + const { data: session, status } = useSession(); + + const signInAnon = (e: FormEvent) => { + e.preventDefault(); + signIn("credentials", { + redirect: false, + message: "Signing in as guest", + callbackUrl: `https://${host}`, + }).then((data) => { + // async sign-in returned + console.log(data); + router.replace(data?.url || Routes.Root); + }); + }; + + useEffect(() => { + console.log(session); + }, [session]); return ( @@ -88,6 +111,25 @@ const SignIn: NextPage< {providers?.email && csrfToken && host && ( )} + {providers?.credentials && ( +
+
+ {/* */} +
+
+ +

Continue as Guest

+
+
+
+ )}

By clicking continue, you agree to our non-existent{" "} diff --git a/src/server/trpc/context.ts b/src/server/trpc/context.ts index da4e0bd..b032a24 100644 --- a/src/server/trpc/context.ts +++ b/src/server/trpc/context.ts @@ -34,6 +34,7 @@ export const createContext = async ( | NodeHTTPCreateContextFnOptions ) => { const session = await getSession(opts); + console.log("create context session", session); return await createContextInner({ session, From d0d4648c571730223d3a8995c3d66264bbd83122 Mon Sep 17 00:00:00 2001 From: Nick Leslie Date: Tue, 23 Jan 2024 17:38:51 -0500 Subject: [PATCH 3/3] Added guest login. Refactored some pages --- package.json | 4 + pnpm-lock.yaml | 70 +++- src/components/header/Header.tsx | 4 +- src/components/header/Menu.tsx | 74 +++++ src/components/header/Notification.tsx | 97 ++++++ src/components/header/menu/Menu.tsx | 18 - src/components/header/menu/MenuBtn.tsx | 16 - src/components/header/menu/MenuItem.tsx | 22 -- src/components/header/menu/MenuPanel.tsx | 28 -- .../header/notification/Notification.tsx | 28 -- .../header/notification/NotificationBtn.tsx | 23 -- .../header/notification/NotificationItem.tsx | 21 -- .../header/notification/NotificationPanel.tsx | 38 --- src/components/signin/EmailLogin.tsx | 62 ---- src/components/signin/VerificationStep.tsx | 57 ---- src/components/ui/Btn.tsx | 64 ++-- src/constants/app.constants.ts | 6 + src/enums/signup-form-id.enum.ts | 5 + src/models/email-signup-form-data.model.ts | 7 - src/pages/add_a_friend.tsx | 35 +- src/pages/api/auth/[...nextauth].ts | 281 +++++++--------- src/pages/index.tsx | 9 +- src/pages/sign_in.tsx | 312 +++++++++++++----- src/server/client/email/base-email-client.ts | 35 ++ src/server/client/email/email-client.ts | 84 +++++ src/server/common/get-server-auth-session.ts | 12 +- src/server/provider/global-provider.ts | 45 ++- src/server/services/user.service.ts | 14 + src/server/trpc/context.ts | 3 +- src/server/trpc/trpc.ts | 2 +- 30 files changed, 825 insertions(+), 651 deletions(-) create mode 100644 src/components/header/Menu.tsx create mode 100644 src/components/header/Notification.tsx delete mode 100644 src/components/header/menu/Menu.tsx delete mode 100644 src/components/header/menu/MenuBtn.tsx delete mode 100644 src/components/header/menu/MenuItem.tsx delete mode 100644 src/components/header/menu/MenuPanel.tsx delete mode 100644 src/components/header/notification/Notification.tsx delete mode 100644 src/components/header/notification/NotificationBtn.tsx delete mode 100644 src/components/header/notification/NotificationItem.tsx delete mode 100644 src/components/header/notification/NotificationPanel.tsx delete mode 100644 src/components/signin/EmailLogin.tsx delete mode 100644 src/components/signin/VerificationStep.tsx delete mode 100644 src/models/email-signup-form-data.model.ts create mode 100644 src/server/client/email/base-email-client.ts create mode 100644 src/server/client/email/email-client.ts diff --git a/package.json b/package.json index aebf188..283e7eb 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "@trpc/next": "10.0.0-rc.4", "@trpc/react-query": "10.0.0-rc.4", "@trpc/server": "10.0.0-rc.4", + "cookies": "^0.9.1", "dotenv": "16.0.3", "fabric": "github:ncpleslie/fabric.js", "fabricjs-react": "github:ncpleslie/fabricjs-react", @@ -57,6 +58,7 @@ "react-toastify": "9.1.1", "resend": "^2.0.0", "superjson": "1.9.1", + "uuid": "^9.0.1", "ws": "8.11.0", "zod": "3.22.4", "zustand": "4.3.2" @@ -64,12 +66,14 @@ "devDependencies": { "@testing-library/jest-dom": "^6.2.0", "@testing-library/react": "^14.1.2", + "@types/cookies": "^0.7.10", "@types/jest": "^29.5.11", "@types/next-pwa": "^5.6.2", "@types/node": "^18.11.9", "@types/nodemailer": "^6.4.7", "@types/react": "^18.2.48", "@types/react-dom": "^18.2.18", + "@types/uuid": "^9.0.7", "@types/ws": "^8.5.3", "@typescript-eslint/eslint-plugin": "^5.43.0", "@typescript-eslint/parser": "^5.43.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 510c58b..f365677 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,9 @@ dependencies: '@trpc/server': specifier: 10.0.0-rc.4 version: 10.0.0-rc.4 + cookies: + specifier: ^0.9.1 + version: 0.9.1 dotenv: specifier: 16.0.3 version: 16.0.3 @@ -89,6 +92,9 @@ dependencies: superjson: specifier: 1.9.1 version: 1.9.1 + uuid: + specifier: ^9.0.1 + version: 9.0.1 ws: specifier: 8.11.0 version: 8.11.0 @@ -106,6 +112,9 @@ devDependencies: '@testing-library/react': specifier: ^14.1.2 version: 14.1.2(react-dom@18.2.0)(react@18.2.0) + '@types/cookies': + specifier: ^0.7.10 + version: 0.7.10 '@types/jest': specifier: ^29.5.11 version: 29.5.11 @@ -124,6 +133,9 @@ devDependencies: '@types/react-dom': specifier: ^18.2.18 version: 18.2.18 + '@types/uuid': + specifier: ^9.0.7 + version: 9.0.7 '@types/ws': specifier: ^8.5.3 version: 8.5.3 @@ -2882,13 +2894,20 @@ packages: dependencies: '@types/connect': 3.4.35 '@types/node': 18.11.9 - dev: false /@types/connect@3.4.35: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: '@types/node': 18.11.9 - dev: false + + /@types/cookies@0.7.10: + resolution: {integrity: sha512-hmUCjAk2fwZVPPkkPBcI7jGLIR5mg4OVoNMBwU6aVsMm/iNPY7z9/R+x2fSwLt/ZXoGua6C5Zy2k5xOo9jUyhQ==} + dependencies: + '@types/connect': 3.4.35 + '@types/express': 4.17.16 + '@types/keygrip': 1.0.6 + '@types/node': 18.11.9 + dev: true /@types/eslint-scope@3.7.7: resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} @@ -2917,7 +2936,6 @@ packages: '@types/node': 18.11.9 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 - dev: false /@types/express@4.17.16: resolution: {integrity: sha512-LkKpqRZ7zqXJuvoELakaFYuETHjZkSol8EV6cNnyishutDBCCdv6+dsKPbKkCcIk57qRphOLY5sEgClw1bO3gA==} @@ -2926,7 +2944,6 @@ packages: '@types/express-serve-static-core': 4.17.33 '@types/qs': 6.9.7 '@types/serve-static': 1.15.0 - dev: false /@types/glob@7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} @@ -2998,6 +3015,10 @@ packages: '@types/node': 18.11.9 dev: false + /@types/keygrip@1.0.6: + resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==} + dev: true + /@types/linkify-it@3.0.5: resolution: {integrity: sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==} requiresBuild: true @@ -3027,7 +3048,6 @@ packages: /@types/mime@3.0.1: resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} - dev: false /@types/minimatch@5.1.2: resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} @@ -3065,11 +3085,9 @@ packages: /@types/qs@6.9.7: resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} - dev: false /@types/range-parser@1.2.4: resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} - dev: false /@types/react-dom@18.2.18: resolution: {integrity: sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==} @@ -3112,7 +3130,6 @@ packages: dependencies: '@types/mime': 3.0.1 '@types/node': 18.11.9 - dev: false /@types/stack-utils@2.0.3: resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} @@ -3125,6 +3142,10 @@ packages: /@types/trusted-types@2.0.3: resolution: {integrity: sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==} + /@types/uuid@9.0.7: + resolution: {integrity: sha512-WUtIVRUZ9i5dYXefDEAI7sh9/O7jGvHg7Df/5O/gtH3Yabe5odI3UWopVR1qbPXQtvOxWu3mM4XxlYeZtMWF4g==} + dev: true + /@types/ws@8.5.3: resolution: {integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==} dependencies: @@ -4282,6 +4303,14 @@ packages: engines: {node: '>= 0.6'} dev: false + /cookies@0.9.1: + resolution: {integrity: sha512-TG2hpqe4ELx54QER/S3HQ9SRVnQnGBtKUz5bLQWtYAQ+o6GpgMs6sYUvaiJjVxb+UXwhRhAEP3m7LbsIZ77Hmw==} + engines: {node: '>= 0.8'} + dependencies: + depd: 2.0.0 + keygrip: 1.1.0 + dev: false + /copy-anything@3.0.2: resolution: {integrity: sha512-CzATjGXzUQ0EvuvgOCI6A4BGOo2bcVx8B+eC2nF862iv9fopnPQwlrbACakNCHRIJbCSBj+J/9JeDf60k64MkA==} engines: {node: '>=12.13'} @@ -4522,6 +4551,11 @@ packages: dev: false optional: true + /depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + dev: false + /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -5622,7 +5656,7 @@ packages: jsonwebtoken: 9.0.0 jwks-rsa: 3.0.1 node-forge: 1.3.1 - uuid: 9.0.0 + uuid: 9.0.1 optionalDependencies: '@google-cloud/firestore': 6.8.0 '@google-cloud/storage': 6.12.0 @@ -7330,6 +7364,13 @@ packages: dev: false optional: true + /keygrip@1.1.0: + resolution: {integrity: sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==} + engines: {node: '>= 0.6'} + dependencies: + tsscmp: 1.0.6 + dev: false + /kind-of@3.2.2: resolution: {integrity: sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==} engines: {node: '>=0.10.0'} @@ -9563,7 +9604,7 @@ packages: https-proxy-agent: 5.0.1 node-fetch: 2.6.7 stream-events: 1.0.5 - uuid: 9.0.0 + uuid: 9.0.1 transitivePeerDependencies: - encoding - supports-color @@ -9778,6 +9819,11 @@ packages: /tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + /tsscmp@1.0.6: + resolution: {integrity: sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==} + engines: {node: '>=0.6.x'} + dev: false + /tsutils@3.21.0(typescript@4.9.3): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -10005,8 +10051,8 @@ packages: hasBin: true dev: false - /uuid@9.0.0: - resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} + /uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true dev: false diff --git a/src/components/header/Header.tsx b/src/components/header/Header.tsx index 6727c4d..1857220 100644 --- a/src/components/header/Header.tsx +++ b/src/components/header/Header.tsx @@ -3,10 +3,10 @@ import Btn from "../ui/Btn"; import Icon from "../ui/Icon"; import { ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; -import Notification from "./notification/Notification"; +import Notification from "./Notification"; import { trpc } from "../../utils/trpc"; import { useEffect, useState } from "react"; -import Menu from "./menu/Menu"; +import Menu from "./Menu"; import type { NotificationDrawEvent } from "../../models/draw_event.model"; import { Routes } from "../../enums/routes.enum"; diff --git a/src/components/header/Menu.tsx b/src/components/header/Menu.tsx new file mode 100644 index 0000000..36cb151 --- /dev/null +++ b/src/components/header/Menu.tsx @@ -0,0 +1,74 @@ +import { Popover, Transition } from "@headlessui/react"; +import type { PropsWithChildren } from "react"; +import Link from "next/link"; +import Icon from "../ui/Icon"; +import PopoverBtn from "../ui/PopoverBtn"; +import { Routes } from "../../enums/routes.enum"; + +const Menu: React.FC = () => { + return ( + + {({ open }) => ( + <> + + + + )} + + ); +}; + +interface MenuBtnProps { + menuOpen: boolean; +} + +const MenuBtn: React.FC = ({ menuOpen }) => { + return ( + + + + ); +}; + +interface MenuItemProps { + href: string; +} + +const MenuItem: React.FC> = ({ + href, + children, +}) => { + return ( + + {children} + + ); +}; + +const MenuPanel: React.FC = () => { + return ( + + +

+
+ Profile + Find More Friends + Sign Out +
+
+ + + ); +}; + +export default Menu; diff --git a/src/components/header/Notification.tsx b/src/components/header/Notification.tsx new file mode 100644 index 0000000..fb9275b --- /dev/null +++ b/src/components/header/Notification.tsx @@ -0,0 +1,97 @@ +import { Popover, Transition } from "@headlessui/react"; +import Link from "next/link"; +import type { FC } from "react"; +import type { NotificationDrawEvent } from "../../models/draw_event.model"; +import Icon from "../ui/Icon"; +import PopoverBtn from "../ui/PopoverBtn"; +import { useAutoAnimate } from "@formkit/auto-animate/react"; + +interface NotificationProps { + drawEvents: NotificationDrawEvent[]; +} + +const Notification: FC = ({ drawEvents }) => { + if (!drawEvents || drawEvents?.length === 0) { + return <>; + } + + return ( + + {({ open }) => ( + <> + + + + )} + + ); +}; + +interface NotificationBtnProps { + count: number; + menuOpen: boolean; +} + +const NotificationBtn: React.FC = ({ + count, + menuOpen, +}) => { + return ( + + <> + +
{count}
+ +
+ ); +}; + +interface NotificationPanelProps { + events: NotificationDrawEvent[]; +} + +const NotificationPanel: React.FC = ({ events }) => { + const [parent] = useAutoAnimate({ duration: 250 }); + + return ( + + +
+
+ {events.map((event) => ( + + ))} +
+
+
+
+ ); +}; + +interface NotificationItemProps { + event: NotificationDrawEvent; +} + +const NotificationItem: React.FC = ({ event }) => { + return ( + + + {`You have a new drawing from ${event.senderName}`} + + ); +}; + +export default Notification; diff --git a/src/components/header/menu/Menu.tsx b/src/components/header/menu/Menu.tsx deleted file mode 100644 index 74dbc53..0000000 --- a/src/components/header/menu/Menu.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Popover } from "@headlessui/react"; -import MenuBtn from "./MenuBtn"; -import MenuPanel from "./MenuPanel"; - -const Menu: React.FC = () => { - return ( - - {({ open }) => ( - <> - - - - )} - - ); -}; - -export default Menu; diff --git a/src/components/header/menu/MenuBtn.tsx b/src/components/header/menu/MenuBtn.tsx deleted file mode 100644 index a905624..0000000 --- a/src/components/header/menu/MenuBtn.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import Icon from "../../ui/Icon"; -import PopoverBtn from "../../ui/PopoverBtn"; - -interface MenuBtnProps { - menuOpen: boolean; -} - -const MenuBtn: React.FC = ({ menuOpen }) => { - return ( - - - - ); -}; - -export default MenuBtn; diff --git a/src/components/header/menu/MenuItem.tsx b/src/components/header/menu/MenuItem.tsx deleted file mode 100644 index 226b662..0000000 --- a/src/components/header/menu/MenuItem.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import Link from "next/link"; -import type { PropsWithChildren } from "react"; - -interface MenuItemProps { - href: string; -} - -const MenuItem: React.FC> = ({ - href, - children, -}) => { - return ( - - {children} - - ); -}; - -export default MenuItem; diff --git a/src/components/header/menu/MenuPanel.tsx b/src/components/header/menu/MenuPanel.tsx deleted file mode 100644 index 2aad2bd..0000000 --- a/src/components/header/menu/MenuPanel.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Popover, Transition } from "@headlessui/react"; -import { Routes } from "../../../enums/routes.enum"; -import MenuItem from "./MenuItem"; - -const MenuPanel: React.FC = () => { - return ( - - -
-
- Profile - Find More Friends - Sign Out -
-
-
-
- ); -}; - -export default MenuPanel; diff --git a/src/components/header/notification/Notification.tsx b/src/components/header/notification/Notification.tsx deleted file mode 100644 index e4ad52d..0000000 --- a/src/components/header/notification/Notification.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Popover } from "@headlessui/react"; -import type { FC } from "react"; -import type { NotificationDrawEvent } from "../../../models/draw_event.model"; -import NotificationBtn from "./NotificationBtn"; -import NotificationPanel from "./NotificationPanel"; - -interface NotificationProps { - drawEvents: NotificationDrawEvent[]; -} - -const Notification: FC = ({ drawEvents }) => { - if (!drawEvents || drawEvents?.length === 0) { - return <>; - } - - return ( - - {({ open }) => ( - <> - - - - )} - - ); -}; - -export default Notification; diff --git a/src/components/header/notification/NotificationBtn.tsx b/src/components/header/notification/NotificationBtn.tsx deleted file mode 100644 index aa73601..0000000 --- a/src/components/header/notification/NotificationBtn.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import Icon from "../../ui/Icon"; -import PopoverBtn from "../../ui/PopoverBtn"; - -interface NotificationBtnProps { - count: number; - menuOpen: boolean; -} - -const NotificationBtn: React.FC = ({ - count, - menuOpen, -}) => { - return ( - - <> - -
{count}
- -
- ); -}; - -export default NotificationBtn; diff --git a/src/components/header/notification/NotificationItem.tsx b/src/components/header/notification/NotificationItem.tsx deleted file mode 100644 index d339a4a..0000000 --- a/src/components/header/notification/NotificationItem.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import Icon from "../../ui/Icon"; -import Link from "next/link"; -import type { NotificationDrawEvent } from "../../../models/draw_event.model"; - -interface NotificationItemProps { - event: NotificationDrawEvent; -} - -const NotificationItem: React.FC = ({ event }) => { - return ( - - - {`You have a new drawing from ${event.senderName}`} - - ); -}; - -export default NotificationItem; diff --git a/src/components/header/notification/NotificationPanel.tsx b/src/components/header/notification/NotificationPanel.tsx deleted file mode 100644 index 67b3a0e..0000000 --- a/src/components/header/notification/NotificationPanel.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import { Popover, Transition } from "@headlessui/react"; -import { useAutoAnimate } from "@formkit/auto-animate/react"; -import type { NotificationDrawEvent } from "../../../models/draw_event.model"; -import NotificationItem from "./NotificationItem"; - -interface NotificationPanelProps { - events: NotificationDrawEvent[]; -} - -const NotificationPanel: React.FC = ({ events }) => { - const [parent] = useAutoAnimate({ duration: 250 }); - - return ( - - -
-
- {events.map((event) => ( - - ))} -
-
-
-
- ); -}; - -export default NotificationPanel; diff --git a/src/components/signin/EmailLogin.tsx b/src/components/signin/EmailLogin.tsx deleted file mode 100644 index 3c86811..0000000 --- a/src/components/signin/EmailLogin.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { SignUpFormId } from "../../enums/signup-form-id.enum"; -import EmailSignUpFormData from "../../models/email-signup-form-data.model"; -import Btn from "../ui/Btn"; -import FocusableInput from "../ui/FocusableInput"; - -interface EmailLoginProps { - csrfToken?: string; - onSubmit: (formData: EmailSignUpFormData) => Promise; -} - -const EmailLogin: React.FC = ({ csrfToken, onSubmit }) => { - const [form, setForm] = useState({ - [SignUpFormId.Email]: "", - }); - const [loading, setLoading] = useState(false); - - useEffect(() => { - setForm({ [SignUpFormId.Email]: "" }); - }, []); - - const handleFormSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setLoading(true); - await onSubmit(new EmailSignUpFormData(form[SignUpFormId.Email])); - setLoading(false); - }; - - const handleFormUpdate = (id: SignUpFormId, e: React.ChangeEvent) => { - const value = (e.target as HTMLInputElement).value; - setForm((prev) => { - prev[id] = value; - return prev; - }); - }; - - return ( -
-
- - handleFormUpdate(SignUpFormId.Email, e)} - /> -
-
- -

Continue

-
-
-
- ); -}; - -export default EmailLogin; diff --git a/src/components/signin/VerificationStep.tsx b/src/components/signin/VerificationStep.tsx deleted file mode 100644 index d0c1c73..0000000 --- a/src/components/signin/VerificationStep.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { useRouter } from "next/router"; -import React, { useState } from "react"; -import Btn from "../ui/Btn"; -import FocusableInput from "../ui/FocusableInput"; - -interface VerificationStepProps { - email: string; - callbackUrl?: string; -} - -/** - * User has inserted the email and now he can put in the verification code - */ -export const VerificationStep: React.FC = ({ - email, - callbackUrl, -}) => { - const router = useRouter(); - const [code, setCode] = useState(""); - - const onReady = (e: React.FormEvent) => { - e.preventDefault(); - router.replace( - `/api/auth/callback/email?email=${encodeURIComponent( - email - )}&token=${code}${callbackUrl ? `&callbackUrl=${callbackUrl}` : ""}` - ); - }; - - const handleFormUpdate = (e: React.ChangeEvent) => { - const value = (e.target as HTMLInputElement).value; - setCode(value); - }; - - return ( -
-

- Insert the magic code you received in your email -

- - handleFormUpdate(e)} - autocomplete={false} - /> - - -

Continue

-
- - ); -}; diff --git a/src/components/ui/Btn.tsx b/src/components/ui/Btn.tsx index aefdb76..7f213f4 100644 --- a/src/components/ui/Btn.tsx +++ b/src/components/ui/Btn.tsx @@ -1,40 +1,54 @@ import type { PropsWithChildren } from "react"; import Icon from "./Icon"; +import Link from "next/link"; -interface BtnProps { - onClicked?: () => void; - title?: string; - loading?: boolean; - active?: boolean; - className?: string; - style?: React.CSSProperties; - type?: "button" | "submit" | "reset" | undefined; -} +type BtnProps = + | { + onClicked?: () => void; + title?: string; + loading?: boolean; + active?: boolean; + className?: string; + style?: React.CSSProperties; + } & ( + | { + type?: "button" | "submit" | "reset"; + } + | { + href: string; + type: "link"; + } + ); -const Btn: React.FC> = ({ - children, - style, - className, - type, - loading, - title, - onClicked, -}) => { - const btnContent = loading ? ( +const Btn: React.FC> = (props) => { + const btnContent = props.loading ? (
) : ( - children + props.children ); + if (props.type === "link") { + return ( + + {btnContent} + + ); + } + return ( diff --git a/src/constants/app.constants.ts b/src/constants/app.constants.ts index 224db9f..c920029 100644 --- a/src/constants/app.constants.ts +++ b/src/constants/app.constants.ts @@ -17,4 +17,10 @@ export default class AppConstants { */ public static readonly appDescription = "An ephemeral image sharing social network"; + + /** + * The max session age in seconds + * 30 days. + */ + public static readonly maxSessionAgeInSecs = 60 * 60 * 24 * 30; } diff --git a/src/enums/signup-form-id.enum.ts b/src/enums/signup-form-id.enum.ts index af36d8d..145cbc4 100644 --- a/src/enums/signup-form-id.enum.ts +++ b/src/enums/signup-form-id.enum.ts @@ -6,4 +6,9 @@ export enum SignUpFormId { * The email form id. */ Email = "email", + + /** + * The verification code form id. + */ + VerificationCode = "verificationCode", } diff --git a/src/models/email-signup-form-data.model.ts b/src/models/email-signup-form-data.model.ts deleted file mode 100644 index e647dec..0000000 --- a/src/models/email-signup-form-data.model.ts +++ /dev/null @@ -1,7 +0,0 @@ -export default class EmailSignUpFormData { - constructor(email: string) { - this.email = email; - } - - public email: string; -} diff --git a/src/pages/add_a_friend.tsx b/src/pages/add_a_friend.tsx index 572997e..12e153d 100644 --- a/src/pages/add_a_friend.tsx +++ b/src/pages/add_a_friend.tsx @@ -1,7 +1,6 @@ import type { CreateNextContextOptions } from "@trpc/server/adapters/next"; import type { InferGetServerSidePropsType, NextPage } from "next"; -import { useRouter } from "next/router"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import FadeIn from "../components/transitions/FadeIn"; import Btn from "../components/ui/Btn"; import FocusableInput from "../components/ui/FocusableInput"; @@ -39,8 +38,9 @@ export async function getServerSideProps(context: CreateNextContextOptions) { const AddAFriend: NextPage< InferGetServerSidePropsType > = ({ friends }) => { - const router = useRouter(); const [searchInput, setSearchInput] = useState(""); + const [friendId, setFriendId] = useState(""); + const { data: foundUsers, error: searchFriendError, @@ -70,15 +70,10 @@ const AddAFriend: NextPage< return; } + setFriendId(user.id); mutateAddFriend({ id: user.id }); }; - useEffect(() => { - if (addFriendSuccess) { - router.replace(Routes.Root); - } - }, [addFriendSuccess]); - return (
@@ -116,9 +111,21 @@ const AddAFriend: NextPage< )}
)} - - Search - +
+ + Search + + {addFriendSuccess && ( + + Done + + )} +
@@ -169,8 +176,8 @@ const AddAFriend: NextPage< ))} diff --git a/src/pages/api/auth/[...nextauth].ts b/src/pages/api/auth/[...nextauth].ts index a6a358d..2b4ea51 100644 --- a/src/pages/api/auth/[...nextauth].ts +++ b/src/pages/api/auth/[...nextauth].ts @@ -1,183 +1,136 @@ -import type { Account, Profile, Session, Theme, User } from "next-auth"; +import Cookies from "cookies"; import NextAuth, { type NextAuthOptions } from "next-auth"; import EmailProvider from "next-auth/providers/email"; import CredentialsProvider from "next-auth/providers/credentials"; import { PrismaAdapter } from "@next-auth/prisma-adapter"; -import { Routes } from "../../../enums/routes.enum"; -import { prisma } from "../../../server/domain/db/client"; -import { env } from "../../../env/server"; -import { Resend } from "resend"; +import { decode, encode } from "next-auth/jwt"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { v4 as uuid } from "uuid"; import AppConstants from "../../../constants/app.constants"; -import { AdapterUser } from "next-auth/adapters"; -import { JWT } from "next-auth/jwt"; -import { connect } from "http2"; +import { + emailClient, + userService, +} from "../../../server/provider/global-provider"; +import { env } from "../../../env/server"; +import { prisma } from "../../../server/domain/db/client"; +import { Routes } from "../../../enums/routes.enum"; -export const authOptions: NextAuthOptions = { - callbacks: { - async jwt({ - token, - account, - profile, - }: { - token: JWT; - account: Account | null; - profile?: Profile; - }): Promise { - if (!token.provider) { - token.provider = "anonymous"; - } - return token; - }, - async session({ - session, - token, - user, - }: { - session: Session & { token_provider?: {} }; - token: JWT; - user?: AdapterUser; - }): Promise { - console.log("session", session); - console.log("user", user); - console.log("token", token); - let sessionUser = user; +export const handler = async (req: NextApiRequest, res: NextApiResponse) => { + const data = requestWrapper(req, res); + return await NextAuth(...data); +}; - if (!sessionUser && session.user?.email) { - sessionUser = (await prisma.user.findUnique({ - where: { - email: session.user.email, - }, - })) as AdapterUser; - } +export default handler; - if (session.user) { - // TODO: Fix this - session.user["id"] = user?.id || sessionUser?.id || ""; - } +export function requestWrapper( + req: NextApiRequest, + res: NextApiResponse +): [req: NextApiRequest, res: NextApiResponse, opts: NextAuthOptions] { + const generateSessionToken = () => uuid(); - // don't make the token (JWT) contents available to the client session (JWT), but flag that they're server-side - if (token.provider) { - session.token_provider = token.provider; - } - return session; - }, - }, - adapter: PrismaAdapter(prisma), - providers: [ - // This magic link auth process is based off https://www.ramielcreations.com/nexth-auth-magic-code - // and https://github.com/nextauthjs/next-auth/issues/4965#issuecomment-1189094806 - EmailProvider({ - from: env.EMAIL_FROM, - maxAge: 5 * 60, - async generateVerificationToken() { - // TODO: This isn't crypto safe. Needs updating - return [...Array(6)].map(() => (Math.random() * 10) | 0).join(``); - }, - async sendVerificationRequest({ identifier: email, url, token, theme }) { - const { host } = new URL(url); + const fromDate = (time: number, date = Date.now()) => + new Date(date + time * 1000); - const resend = new Resend(env.RESEND_API_KEY); - await resend.emails.send({ - from: env.EMAIL_FROM, - to: email, - subject: `${AppConstants.appTitle} Access Code: ${token}`, - html: html({ url, host, theme, token }), - }); - }, - }), - CredentialsProvider({ - name: "anonymous", - credentials: {}, - async authorize(credentials, req) { - return createAnonymousUser(); - }, - }), - ], - session: { - strategy: "jwt", - }, - pages: { - signIn: Routes.SignIn, - newUser: Routes.NewUser, - signOut: Routes.SignOut, - }, - secret: env.NEXTAUTH_SECRET, - debug: env.NODE_ENV !== "production", -}; + const adapter = PrismaAdapter(prisma); -export default NextAuth(authOptions); + const opts: NextAuthOptions = { + adapter: adapter, + callbacks: { + session({ session, user }) { + if (session.user) { + session.user.id = user.id; + } -/** - * Email HTML body - * Insert invisible space into domains from being turned into a hyperlink by email - * clients like Outlook and Apple mail, as this is confusing because it seems - * like they are supposed to click on it to sign in. - * - * @note We don't add the email address to avoid needing to escape it, if you do, remember to sanitize it! - */ -function html(params: { - url: string; - host: string; - theme: Theme; - token: string; -}) { - const { host, theme, token } = params; + return session; + }, + async signIn({ user }) { + // Check if this sign in callback is being called in the credentials authentication flow. If so, use the next-auth adapter to create a session entry in the database (SignIn is called after authorize so we can safely assume the user is valid and already authenticated). + if ( + req.query.nextauth?.includes("callback") && + req.query.nextauth?.includes("credentials") && + req.method === "POST" + ) { + if (user) { + const sessionToken = generateSessionToken(); + const sessionExpiry = fromDate(AppConstants.maxSessionAgeInSecs); - const escapedHost = host.replace(/\./g, "​."); + await adapter.createSession?.({ + sessionToken: sessionToken, + userId: user.id, + expires: sessionExpiry, + }); - const brandColor = theme.brandColor || "#346df1"; - const color = { - background: "#f9f9f9", - text: "#444", - mainBackground: "#fff", - buttonBackground: brandColor, - buttonBorder: brandColor, - buttonText: theme.buttonText || "#fff", - }; + const cookies = new Cookies(req, res); - return ` - - - - - - - - - - - -
- Sign in to ${escapedHost} -
- - - - -
${token}
-
- If you did not request this email you can safely ignore it. -
- -`; -} + cookies.set("next-auth.session-token", sessionToken, { + expires: sessionExpiry, + }); + } + } -const createAnonymousUser = async () => { - // generate a random name and email for this anonymous user - const id = [...Array(6)].map(() => (Math.random() * 10) | 0).join(``); - const user = await prisma.user.create({ - data: { - id: id, - email: `guest-${id}@guest.com`, - emailVerified: new Date(), + return true; + }, }, - }); + jwt: { + encode: async ({ token, secret, maxAge }) => { + if ( + req.query.nextauth?.includes("callback") && + req.query.nextauth.includes("credentials") && + req.method === "POST" + ) { + const cookies = new Cookies(req, res); + const cookie = cookies.get("next-auth.session-token"); + if (cookie) return cookie; + else return ""; + } + // Revert to default behavior when not in the credentials provider callback flow + return encode({ token, secret, maxAge }); + }, + decode: async ({ token, secret }) => { + if ( + req.query.nextauth?.includes("callback") && + req.query.nextauth.includes("credentials") && + req.method === "POST" + ) { + return null; + } - console.log("user", user); + // Revert to default behavior when not in the credentials provider callback flow + return decode({ token, secret }); + }, + }, + pages: { + signIn: Routes.SignIn, + newUser: Routes.NewUser, + signOut: Routes.SignOut, + }, + secret: env.NEXTAUTH_SECRET, + debug: env.NODE_ENV !== "production", + providers: [ + // Credentials provider based on the following repo: + // https://github.com/abehidek/sandbox/tree/main/t3-stack/auth-credentials-db-session + CredentialsProvider({ + name: "anonymous", + credentials: {}, + async authorize() { + return await userService.createAnonymousUserAsync(); + }, + }), + // This magic link auth process is based off https://www.ramielcreations.com/nexth-auth-magic-code + // and https://github.com/nextauthjs/next-auth/issues/4965#issuecomment-1189094806 + EmailProvider({ + from: env.EMAIL_FROM, + maxAge: 5 * 60, + async generateVerificationToken() { + return uuid().substring(0, 6).toUpperCase(); + }, + async sendVerificationRequest({ identifier: email, url, token }) { + const { host } = new URL(url); + await emailClient.sendVerificationAsync(email, token, url, host); + }, + }), + ], + }; - return user; -}; + return [req, res, opts]; +} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index eef7a7f..fc7d22a 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -11,13 +11,11 @@ import AuthAppShell from "../layout/AuthAppShell"; export async function getServerSideProps(context: CreateNextContextOptions) { const ctx = await createContext(context); - const allImages = []; try { - const userId = ctx.session?.user?.id; - if (!userId) { - // Redirect user + const user = ctx.session?.user; + if (!user?.id) { return { redirect: { destination: Routes.SignIn, @@ -25,8 +23,9 @@ export async function getServerSideProps(context: CreateNextContextOptions) { }, }; } + const imageEvents = - (await ctx.userService.getAllImageEventsForUserAsync(userId)) || []; + (await ctx.userService.getAllImageEventsForUserAsync(user?.id)) || []; const images = imageEvents?.map( (image) => new NotificationDrawEvent(image) diff --git a/src/pages/sign_in.tsx b/src/pages/sign_in.tsx index b22e96a..5ff67f9 100644 --- a/src/pages/sign_in.tsx +++ b/src/pages/sign_in.tsx @@ -5,20 +5,17 @@ import { signIn, getCsrfToken, getSession, - useSession, } from "next-auth/react"; import Head from "next/head"; -import React, { FormEvent, useEffect, useState } from "react"; -import EmailLogin from "../components/signin/EmailLogin"; -import { VerificationStep } from "../components/signin/VerificationStep"; +import React, { type FormEvent, useState } from "react"; import { Routes } from "../enums/routes.enum"; import UnauthAppShell from "../layout/UnauthAppShell"; -import type EmailSignUpFormData from "../models/email-signup-form-data.model"; import Icon from "../components/ui/Icon"; import AppConstants from "../constants/app.constants"; import Btn from "../components/ui/Btn"; -import { router } from "../server/trpc/trpc"; import { useRouter } from "next/router"; +import FocusableInput from "../components/ui/FocusableInput"; +import { SignUpFormId } from "../enums/signup-form-id.enum"; export async function getServerSideProps(context: CtxOrReq | undefined) { const session = await getSession(context); @@ -45,24 +42,26 @@ const SignIn: NextPage< > = ({ providers, csrfToken, host }) => { const title = `${AppConstants.appTitle} | Sign In`; const router = useRouter(); - const { data: session, status } = useSession(); - const signInAnon = (e: FormEvent) => { - e.preventDefault(); - signIn("credentials", { - redirect: false, - message: "Signing in as guest", - callbackUrl: `https://${host}`, - }).then((data) => { - // async sign-in returned - console.log(data); - router.replace(data?.url || Routes.Root); + const signInAnon = async () => { + await signIn("credentials", { + redirect: true, + callbackUrl: Routes.NewUser, }); }; - useEffect(() => { - console.log(session); - }, [session]); + const signInEmail = async (email: string) => { + await signIn("email", { email: email, redirect: false }); + }; + + const handleVerificationCode = async (email: string, code: string) => { + const callbackUrl = `https://${host}`; + await router.replace( + `/api/auth/callback/email?email=${encodeURIComponent( + email + )}&token=${code.toUpperCase()}&callbackUrl=${callbackUrl}` + ); + }; return ( @@ -71,29 +70,7 @@ const SignIn: NextPage<
-
-
- An image of a stickman -
- - {AppConstants.appTitle} -
-
-
-

- The ephemeral image sharing application -

-

- Find your friends, draw an image, and send it to them. Once - they view it, it's gone forever -

-
-
-
+
@@ -107,48 +84,32 @@ const SignIn: NextPage< You'll be emailed a magic code to continue the sign up

-
- {providers?.email && csrfToken && host && ( - +
+ {providers?.email && csrfToken && ( + )} - {providers?.credentials && ( -
-
- {/* */} -
-
- -

Continue as Guest

-
-
-
+
+
+ +
+
+ + Or continue as + +
+
+ {providers?.credentials && csrfToken && ( + )} +
-

- By clicking continue, you agree to our non-existent{" "} - - Terms of Service - {" "} - and{" "} - - Privacy Policy - - . We are only going to store your email address and the images - you might send. -

@@ -157,33 +118,204 @@ const SignIn: NextPage< ); }; +interface GuestLoginSectionProps { + csrfToken?: string; + onGuestLogin: () => Promise; +} + +const GuestLoginSection: React.FC = ({ + csrfToken, + onGuestLogin, +}) => { + const [loading, setLoading] = useState(false); + + const onSubmit = async (e: FormEvent) => { + e.preventDefault(); + setLoading(true); + await onGuestLogin(); + setLoading(false); + }; + + return ( +
+ + +

Guest

+
+
+ ); +}; + interface EmailLoginSectionProps { - csrfToken: string; - host: string; + csrfToken?: string; + onEmailLogin: (email: string) => Promise; + onVerification: (email: string, code: string) => Promise; } const EmailLoginSection: React.FC = ({ csrfToken, - host, + onEmailLogin, + onVerification, }) => { const [showVerificationStep, setShowVerificationStep] = useState(false); const [email, setEmail] = useState(""); - const handleEmailSubmit = async (emailFormData: EmailSignUpFormData) => { - setEmail(emailFormData.email); - await signIn("email", { email: emailFormData.email, redirect: false }); + + const onEmailSubmit = async (email: string) => { + setEmail(email); + await onEmailLogin(email); setShowVerificationStep(true); }; + const onVerificationSubmit = async (code: string) => { + await onVerification(email, code); + }; + return (
{!showVerificationStep && ( - + )} {showVerificationStep && ( - + )}
); }; +interface EmailLoginProps { + csrfToken?: string; + onSubmit: (email: string) => Promise; +} + +const EmailLogin: React.FC = ({ csrfToken, onSubmit }) => { + const [loading, setLoading] = useState(false); + + const handleFormSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setLoading(true); + const form = new FormData(e.target as HTMLFormElement); + const email = form.get(SignUpFormId.Email) as string; + await onSubmit(email); + setLoading(false); + }; + + return ( +
+
+ + +
+
+ +

Continue

+
+
+
+ ); +}; + +interface VerificationStepProps { + onSubmit: (verificationCode: string) => Promise; +} + +/** + * User has inserted the email and now he can put in the verification code + */ +const VerificationStep: React.FC = ({ onSubmit }) => { + const [loading, setLoading] = useState(false); + + const handleFormSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + setLoading(true); + const form = new FormData(e.target as HTMLFormElement); + const verification = form.get(SignUpFormId.VerificationCode) as string; + await onSubmit(verification); + setLoading(false); + }; + + return ( +
+

+ Insert the magic code you received in your email +

+ + + + +

Continue

+
+ + ); +}; + +const HeroSection = () => { + return ( +
+
+ An image of a stickman +
+ + {AppConstants.appTitle} +
+
+
+

The ephemeral image sharing application

+

+ Find your friends, draw an image, and send it to them. Once they + view it, it's gone forever +

+
+
+
+ ); +}; + +const DisclaimerSection = () => { + return ( +

+ By clicking continue, you agree to our non-existent{" "} + + Terms of Service + {" "} + and{" "} + + Privacy Policy + + . We are only going to store your email address and the images you might + send. +

+ ); +}; + export default SignIn; diff --git a/src/server/client/email/base-email-client.ts b/src/server/client/email/base-email-client.ts new file mode 100644 index 0000000..eb305bb --- /dev/null +++ b/src/server/client/email/base-email-client.ts @@ -0,0 +1,35 @@ +import { Resend } from "resend"; + +/** + * Base email client. + */ +export default abstract class BaseEmailClient { + protected client: Resend; + protected fromAddress: string; + + /** + * Creates an instance of base email client. + * @param resendApiKey - The Resend API key. + * @param fromAddress - The fromAddress to send emails from. + */ + constructor(resendApiKey: string, fromAddress: string) { + this.client = new Resend(resendApiKey); + this.fromAddress = fromAddress; + } + + /** + * Sends an email with an HTML body. + * @param to - The email address to send to. + * @param subject - The subject of the email. + * @param html - The HTML body of the email. + * @returns - A promise that resolves when the email is sent. + */ + protected async sendAsync(to: string, subject: string, html: string) { + await this.client.emails.send({ + from: this.fromAddress, + to: to, + subject: subject, + html: html, + }); + } +} diff --git a/src/server/client/email/email-client.ts b/src/server/client/email/email-client.ts new file mode 100644 index 0000000..ce27296 --- /dev/null +++ b/src/server/client/email/email-client.ts @@ -0,0 +1,84 @@ +import AppConstants from "../../../constants/app.constants"; +import BaseEmailClient from "./base-email-client"; + +/** + * Email client. + */ +export default class EmailClient extends BaseEmailClient { + /** + * Creates an instance of email client. + * @param emailClientApiKey - The email client API key. + * @param fromAddress - The address to send emails from. + */ + constructor(emailClientApiKey: string, fromAddress: string) { + super(emailClientApiKey, fromAddress); + } + + /** + * Sends a verification email. + * @param to - The email address to send to. + * @param token - The verification token. + * @param url - The URL to verify the token at. + * @param host - The host to display in the email. + * @returns - A promise that resolves when the email is sent. + */ + public async sendVerificationAsync( + to: string, + token: string, + url: string, + host: string + ) { + const subject = `${AppConstants.appTitle} Access Code: ${token}`; + const html = this.generateVerificationHtml(url, host, token); + await this.sendAsync(to, subject, html); + } + + /** + * Email HTML body + * Insert invisible space into domains from being turned into a hyperlink by email + * clients like Outlook and Apple mail, as this is confusing because it seems + * like they are supposed to click on it to sign in. + */ + private generateVerificationHtml(url: string, host: string, token: string) { + const escapedHost = host.replace(/\./g, "​."); + const brandColor = "#346df1"; + const color = { + background: "#f9f9f9", + text: "#444", + mainBackground: "#fff", + buttonBackground: brandColor, + buttonBorder: brandColor, + buttonText: "#fff", + }; + + return ` + + + + + + + + + + + +
+ Sign in to ${escapedHost} +
+ + + + +
${token}
+
+ If you did not request this email you can safely ignore it. +
+ +`; + } +} diff --git a/src/server/common/get-server-auth-session.ts b/src/server/common/get-server-auth-session.ts index 8323ff2..79920c9 100644 --- a/src/server/common/get-server-auth-session.ts +++ b/src/server/common/get-server-auth-session.ts @@ -1,14 +1,14 @@ -import { type GetServerSidePropsContext } from "next"; -import { unstable_getServerSession } from "next-auth"; -import { authOptions } from "../../pages/api/auth/[...nextauth]"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { getServerSession } from "next-auth"; +import { requestWrapper } from "../../pages/api/auth/[...nextauth]"; /** * Wrapper for unstable_getServerSession https://next-auth.js.org/configuration/nextjs * See example usage in trpc createContext or the restricted API route */ export const getServerAuthSession = async (ctx: { - req: GetServerSidePropsContext["req"]; - res: GetServerSidePropsContext["res"]; + req: NextApiRequest; + res: NextApiResponse; }) => { - return await unstable_getServerSession(ctx.req, ctx.res, authOptions); + return await getServerSession(...requestWrapper(ctx.req, ctx.res)); }; diff --git a/src/server/provider/global-provider.ts b/src/server/provider/global-provider.ts index 8c5fb0b..c12c1d5 100644 --- a/src/server/provider/global-provider.ts +++ b/src/server/provider/global-provider.ts @@ -4,25 +4,31 @@ import ImageEventService from "../services/image-event.service"; import UserService from "../services/user.service"; import { env } from "../../env/server.js"; import GlobalRef from "./global-ref"; +import EmailClient from "../client/email/email-client"; /** * Global provider for services and other singletons that should be shared across the application. */ class GlobalProvider { - private static userServiceRef = new GlobalRef(UserService.name); + private static emailClientRef = new GlobalRef(EmailClient.name); private static imageEventServiceRef = new GlobalRef( ImageEventService.name ); + private static userServiceRef = new GlobalRef(UserService.name); /** - * Gets the user service. - * @returns - The user service. + * Gets the email client. + * @returns - The email client. */ - static getUserService(): UserService { - if (!GlobalProvider.userServiceRef.value) { - GlobalProvider.userServiceRef.value = new UserService(UserDB); + static getEmailClient() { + if (!GlobalProvider.emailClientRef.value) { + GlobalProvider.emailClientRef.value = new EmailClient( + env.RESEND_API_KEY, + env.EMAIL_FROM + ); } - return GlobalProvider.userServiceRef.value; + + return GlobalProvider.emailClientRef.value; } /** @@ -45,18 +51,37 @@ class GlobalProvider { storageClient ); } + return GlobalProvider.imageEventServiceRef.value; } + + /** + * Gets the user service. + * @returns - The user service. + */ + static getUserService(): UserService { + if (!GlobalProvider.userServiceRef.value) { + GlobalProvider.userServiceRef.value = new UserService(UserDB); + } + + return GlobalProvider.userServiceRef.value; + } } /** - * The user service. - * @see UserService + * The email client. + * @see EmailClient */ -export const userService = GlobalProvider.getUserService(); +export const emailClient = GlobalProvider.getEmailClient(); /** * The image event service. * @see ImageEventService */ export const imageEventService = GlobalProvider.getImageEventService(); + +/** + * The user service. + * @see UserService + */ +export const userService = GlobalProvider.getUserService(); diff --git a/src/server/services/user.service.ts b/src/server/services/user.service.ts index 7a18441..503d771 100644 --- a/src/server/services/user.service.ts +++ b/src/server/services/user.service.ts @@ -2,6 +2,7 @@ import { type Friend, type User, type IUserDomain } from "../domain/db/client"; import NotFoundError from "./errors/not-found.error"; import ValidationError from "./errors/validation.error"; import { exclude } from "../../utils/helper.utils"; +import { v4 as uuid } from "uuid"; /** * The user service for interacting with users in the database. @@ -15,6 +16,19 @@ export default class UserService { */ constructor(private db: IUserDomain) {} + /** + * Creates an anonymous user. + * @returns - A new anonymous user. + */ + public async createAnonymousUserAsync() { + const id = uuid(); + return await this.db.create({ + data: { + email: `guest-${id}@guest.com`, + }, + }); + } + /** * Deletes a friend from a user by id. * @param userId - The id of the user with the friend. diff --git a/src/server/trpc/context.ts b/src/server/trpc/context.ts index b032a24..bf9bf42 100644 --- a/src/server/trpc/context.ts +++ b/src/server/trpc/context.ts @@ -33,8 +33,7 @@ export const createContext = async ( | CreateNextContextOptions | NodeHTTPCreateContextFnOptions ) => { - const session = await getSession(opts); - console.log("create context session", session); + const session = await getSession({ req: opts.req }); return await createContextInner({ session, diff --git a/src/server/trpc/trpc.ts b/src/server/trpc/trpc.ts index 28dbad4..3adb251 100644 --- a/src/server/trpc/trpc.ts +++ b/src/server/trpc/trpc.ts @@ -2,7 +2,6 @@ import { initTRPC, TRPCError } from "@trpc/server"; import superjson from "superjson"; import { ZodError } from "zod"; import DomainNotFoundError from "../services/errors/not-found.error"; - import { type Context } from "./context"; const t = initTRPC.context().create({ @@ -39,6 +38,7 @@ const isAuthed = t.middleware(({ ctx, next }) => { if (!ctx.session || !ctx.session.user) { throw new TRPCError({ code: "UNAUTHORIZED" }); } + return next({ ctx: { // infers the `session` as non-nullable