From d1fb6d355e975c1d1d63085d30600af6e8fbf671 Mon Sep 17 00:00:00 2001
From: Martin Domajnko <35891136+martines3000@users.noreply.github.com>
Date: Sat, 2 Mar 2024 21:05:26 +0100
Subject: [PATCH] feat: migrate planetscale to supabase (#572)

---
 .changeset/twenty-turtles-approve.md          |   5 +
 packages/dapp/.env.example                    |   4 +-
 packages/dapp/package.json                    |   3 -
 packages/dapp/prisma/schema.prisma            |  15 -
 .../page.tsx                                  |   8 +-
 packages/dapp/src/app/[locale]/app/layout.tsx |   4 +-
 .../src/app/api/encrypted-session/route.ts    | 118 ++++++
 .../src/app/api/qr-code-session/[id]/route.ts | 151 -------
 .../src/components/AppBottomBar/index.tsx     |   2 +-
 .../ConnectionModal/CreateConnectionModal.tsx |  90 ++++-
 .../ChooseDeviceView.tsx                      |   0
 .../ConnectDeviceView.tsx                     | 110 ++---
 .../CredentialView.tsx                        |  10 +-
 .../ScanQRCodeView.tsx                        |  65 ++-
 .../StartFlowView/CredentialOfferView.tsx     |   8 +-
 .../StartFlowView/OIDCAuthView.tsx            |   8 +-
 .../StartFlowView/PolygonAuthView.tsx         |   8 +-
 .../StartFlowView/index.tsx                   |  10 +-
 .../index.tsx                                 |  72 ++--
 .../EncryptedSessionProvider/index.tsx        | 202 ++++++++++
 .../dapp/src/components/MenuPopover/index.tsx |   2 +-
 .../QRCodeSessionProvider/index.tsx           | 193 ---------
 packages/dapp/src/messages/en.json            |  12 +-
 .../dapp/src/stores/encryptedSessionStore.ts  |  67 ++++
 packages/dapp/src/stores/index.ts             |   2 +-
 packages/dapp/src/stores/sessionStore.ts      |  56 ---
 packages/dapp/src/utils/prisma.ts             |   9 -
 .../dapp/src/utils/supabase/database.types.ts |  32 ++
 pnpm-lock.yaml                                | 377 +++++++++++++-----
 29 files changed, 960 insertions(+), 683 deletions(-)
 create mode 100644 .changeset/twenty-turtles-approve.md
 delete mode 100644 packages/dapp/prisma/schema.prisma
 rename packages/dapp/src/app/[locale]/app/(public)/{qr-code-session => encrypted-session}/page.tsx (63%)
 create mode 100644 packages/dapp/src/app/api/encrypted-session/route.ts
 delete mode 100644 packages/dapp/src/app/api/qr-code-session/[id]/route.ts
 rename packages/dapp/src/components/{QRSessionDisplay => EncryptedSessionDisplay}/ChooseDeviceView.tsx (100%)
 rename packages/dapp/src/components/{QRSessionDisplay => EncryptedSessionDisplay}/ConnectDeviceView.tsx (65%)
 rename packages/dapp/src/components/{QRSessionDisplay => EncryptedSessionDisplay}/CredentialView.tsx (95%)
 rename packages/dapp/src/components/{QRSessionDisplay => EncryptedSessionDisplay}/ScanQRCodeView.tsx (79%)
 rename packages/dapp/src/components/{QRSessionDisplay => EncryptedSessionDisplay}/StartFlowView/CredentialOfferView.tsx (95%)
 rename packages/dapp/src/components/{QRSessionDisplay => EncryptedSessionDisplay}/StartFlowView/OIDCAuthView.tsx (94%)
 rename packages/dapp/src/components/{QRSessionDisplay => EncryptedSessionDisplay}/StartFlowView/PolygonAuthView.tsx (94%)
 rename packages/dapp/src/components/{QRSessionDisplay => EncryptedSessionDisplay}/StartFlowView/index.tsx (86%)
 rename packages/dapp/src/components/{QRSessionDisplay => EncryptedSessionDisplay}/index.tsx (85%)
 create mode 100644 packages/dapp/src/components/EncryptedSessionProvider/index.tsx
 delete mode 100644 packages/dapp/src/components/QRCodeSessionProvider/index.tsx
 create mode 100644 packages/dapp/src/stores/encryptedSessionStore.ts
 delete mode 100644 packages/dapp/src/stores/sessionStore.ts
 delete mode 100644 packages/dapp/src/utils/prisma.ts

diff --git a/.changeset/twenty-turtles-approve.md b/.changeset/twenty-turtles-approve.md
new file mode 100644
index 000000000..c29b518f3
--- /dev/null
+++ b/.changeset/twenty-turtles-approve.md
@@ -0,0 +1,5 @@
+---
+'@blockchain-lab-um/dapp': minor
+---
+
+Migrate Planetscale to Supabase
diff --git a/packages/dapp/.env.example b/packages/dapp/.env.example
index 3ec79d0fc..75576437f 100644
--- a/packages/dapp/.env.example
+++ b/packages/dapp/.env.example
@@ -10,9 +10,7 @@ SEPOLIA_RPC_URL=
 IPFS_GATEWAY=
 POLYGON_RPC_URL=
 POLYGON_MUMBAI_RPC_URL=
-
-# Prisma
-DATABASE_URL=
+=
 
 # Masca version
 NEXT_PUBLIC_MASCA_VERSION=v1.1.0
diff --git a/packages/dapp/package.json b/packages/dapp/package.json
index c5976e96b..5f4b20c1e 100644
--- a/packages/dapp/package.json
+++ b/packages/dapp/package.json
@@ -11,7 +11,6 @@
     "dev": "cross-env next dev",
     "dev:local": "cross-env USE_LOCAL='true' next dev",
     "docker:build": "docker build . -t blockchain-lab-um/dapp:latest",
-    "postinstall": "pnpm prisma generate --schema=./prisma/schema.prisma",
     "lint": "pnpm lint:next && pnpm lint:tsc && pnpm lint:prettier && pnpm lint:stylelint",
     "lint:fix": "next lint . --fix && prettier . --write",
     "lint:next": "next lint",
@@ -28,7 +27,6 @@
     "@headlessui/react": "^1.7.17",
     "@heroicons/react": "^2.0.18",
     "@nextui-org/react": "^2.2.9",
-    "@prisma/client": "^5.7.0",
     "@radix-ui/react-toast": "^1.1.5",
     "@react-oauth/google": "^0.11.1",
     "@supabase/supabase-js": "^2.38.5",
@@ -65,7 +63,6 @@
     "next-sitemap": "^4.2.3",
     "next-themes": "^0.2.1",
     "pino-pretty": "^10.3.1",
-    "prisma": "^5.7.0",
     "qrcode.react": "^3.1.0",
     "qs": "^6.11.2",
     "react": "18.2.0",
diff --git a/packages/dapp/prisma/schema.prisma b/packages/dapp/prisma/schema.prisma
deleted file mode 100644
index e2ad86a3e..000000000
--- a/packages/dapp/prisma/schema.prisma
+++ /dev/null
@@ -1,15 +0,0 @@
-generator client {
-  provider = "prisma-client-js"
-}
-
-datasource db {
-  provider     = "mysql"
-  url          = env("DATABASE_URL")
-  relationMode = "prisma"
-}
-
-model sessions {
-  id   String  @id @default(uuid())
-  data String? @db.VarChar(512)
-  iv   String? @db.VarChar(128)
-}
diff --git a/packages/dapp/src/app/[locale]/app/(public)/qr-code-session/page.tsx b/packages/dapp/src/app/[locale]/app/(public)/encrypted-session/page.tsx
similarity index 63%
rename from packages/dapp/src/app/[locale]/app/(public)/qr-code-session/page.tsx
rename to packages/dapp/src/app/[locale]/app/(public)/encrypted-session/page.tsx
index a32019760..4a42a6042 100644
--- a/packages/dapp/src/app/[locale]/app/(public)/qr-code-session/page.tsx
+++ b/packages/dapp/src/app/[locale]/app/(public)/encrypted-session/page.tsx
@@ -1,17 +1,17 @@
 import { Metadata } from 'next';
 
-import QRCodeSessionDisplay from '@/components/QRSessionDisplay';
+import EncryptedSessionDisplay from '@/components/EncryptedSessionDisplay';
 
 export const metadata: Metadata = {
-  title: 'QR Code Session',
-  description: 'QR Code Session for Masca.',
+  title: 'Encrypted Session',
+  description: 'Encrypted Session for Masca.',
 };
 
 export default function Page() {
   return (
     <div className="flex flex-1 items-center justify-center">
       <div className="dark:bg-navy-blue-800 dark:text-navy-blue-400 w-full rounded-3xl bg-white shadow-lg md:max-w-4xl">
-        <QRCodeSessionDisplay />
+        <EncryptedSessionDisplay />
       </div>
     </div>
   );
diff --git a/packages/dapp/src/app/[locale]/app/layout.tsx b/packages/dapp/src/app/[locale]/app/layout.tsx
index 9b439cfbe..32af1ed85 100644
--- a/packages/dapp/src/app/[locale]/app/layout.tsx
+++ b/packages/dapp/src/app/[locale]/app/layout.tsx
@@ -3,8 +3,8 @@ import clsx from 'clsx';
 import AppBottomBar from '@/components/AppBottomBar';
 import AppNavbar from '@/components/AppNavbar';
 import { CookiesProvider } from '@/components/CookiesProvider';
+import { EncryptedSessionProvider } from '@/components/EncryptedSessionProvider';
 import MascaProvider from '@/components/MascaProvider';
-import QRCodeSessionProvider from '@/components/QRCodeSessionProvider';
 import { SignInModal } from '@/components/SignInModal';
 import ToastWrapper from '@/components/ToastWrapper';
 import WagmiProviderWrapper from '@/components/WagmiProvider';
@@ -30,7 +30,7 @@ export default async function AppLayout({
           </div>
         </div>
         <AppBottomBar />
-        <QRCodeSessionProvider />
+        <EncryptedSessionProvider />
         <SignInModal />
         <CookiesProvider />
       </WagmiProviderWrapper>
diff --git a/packages/dapp/src/app/api/encrypted-session/route.ts b/packages/dapp/src/app/api/encrypted-session/route.ts
new file mode 100644
index 000000000..2bbc5b35a
--- /dev/null
+++ b/packages/dapp/src/app/api/encrypted-session/route.ts
@@ -0,0 +1,118 @@
+import { NextRequest, NextResponse } from 'next/server';
+import { createClient } from '@supabase/supabase-js';
+import jwt from 'jsonwebtoken';
+
+import { Database } from '@/utils/supabase/database.types';
+
+const CORS_HEADERS = {
+  'Access-Control-Allow-Origin': '*',
+  'Access-Control-Allow-Methods': 'GET OPTIONS',
+  'Access-Control-Allow-Headers': 'Content-Type',
+};
+
+export async function GET(request: NextRequest) {
+  try {
+    const token = request.headers.get('Authorization')?.replace('Bearer ', '');
+
+    if (!token) {
+      return new NextResponse('Unauthorized', {
+        status: 401,
+        headers: {
+          ...CORS_HEADERS,
+        },
+      });
+    }
+
+    const user = jwt.verify(token, process.env.SUPABASE_JWT_SECRET!) as {
+      sub: string;
+      address: string;
+      aud: string;
+      role: string;
+      iat: number;
+      exp: number;
+    };
+
+    const supabase = createClient<Database>(
+      process.env.NEXT_PUBLIC_SUPABASE_URL!,
+      process.env.SUPABASE_SECRET_KEY!
+    );
+
+    const { data: selectData, error: selectError } = await supabase
+      .from('encrypted_sessions')
+      .select('id')
+      .eq('user_id', user.sub);
+
+    if (selectError) {
+      return new NextResponse('Internal Server Error', {
+        status: 500,
+        headers: {
+          ...CORS_HEADERS,
+        },
+      });
+    }
+
+    // If session is found delete it
+    if (selectData.length !== 0) {
+      const { error: deleteError } = await supabase
+        .from('encrypted_sessions')
+        .delete()
+        .eq('user_id', user.sub);
+
+      if (deleteError) {
+        return new NextResponse('Internal Server Error', {
+          status: 500,
+          headers: {
+            ...CORS_HEADERS,
+          },
+        });
+      }
+    }
+
+    // Create a new session
+    const { data: insertData, error: insertError } = await supabase
+      .from('encrypted_sessions')
+      .insert({
+        user_id: user.sub,
+      })
+      .select()
+      .limit(1)
+      .single();
+
+    if (insertError || !insertData) {
+      return new NextResponse('Internal Server Error', {
+        status: 500,
+        headers: {
+          ...CORS_HEADERS,
+        },
+      });
+    }
+
+    return NextResponse.json(
+      {
+        sessionId: insertData.id,
+      },
+      {
+        status: 201,
+        headers: {
+          ...CORS_HEADERS,
+        },
+      }
+    );
+  } catch (error) {
+    return new NextResponse('Internal Server Error', {
+      status: 500,
+      headers: {
+        ...CORS_HEADERS,
+      },
+    });
+  }
+}
+
+export async function OPTIONS() {
+  return new NextResponse(null, {
+    status: 200,
+    headers: {
+      ...CORS_HEADERS,
+    },
+  });
+}
diff --git a/packages/dapp/src/app/api/qr-code-session/[id]/route.ts b/packages/dapp/src/app/api/qr-code-session/[id]/route.ts
deleted file mode 100644
index bbd60a888..000000000
--- a/packages/dapp/src/app/api/qr-code-session/[id]/route.ts
+++ /dev/null
@@ -1,151 +0,0 @@
-import { NextRequest, NextResponse } from 'next/server';
-
-import { prisma } from '@/utils/prisma';
-
-const CORS_HEADERS = {
-  'Access-Control-Allow-Origin': '*',
-  'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
-  'Access-Control-Allow-Headers': 'Content-Type',
-};
-
-export async function GET(
-  _: NextRequest,
-  { params: { id } }: { params: { id: string } }
-) {
-  if (!id) {
-    return NextResponse.json(
-      { error_description: 'Missing sessionId parameter' },
-      {
-        status: 400,
-        headers: {
-          ...CORS_HEADERS,
-        },
-      }
-    );
-  }
-
-  // Get session from database
-  const session = await prisma.sessions.findUnique({
-    where: {
-      id,
-    },
-  });
-
-  if (!session) {
-    return NextResponse.json(
-      { error_description: 'Session not found' },
-      {
-        status: 404,
-        headers: {
-          ...CORS_HEADERS,
-        },
-      }
-    );
-  }
-
-  await prisma.sessions.delete({
-    where: {
-      id,
-    },
-  });
-
-  // Get session data
-  return NextResponse.json(
-    { data: session.data, iv: session.iv },
-    {
-      status: 200,
-      headers: {
-        ...CORS_HEADERS,
-      },
-    }
-  );
-}
-
-export async function POST(
-  request: NextRequest,
-  { params: { id } }: { params: { id: string } }
-) {
-  try {
-    const jsonData = await request.json();
-
-    const { data, iv } = jsonData;
-    if (!id) {
-      return NextResponse.json(
-        { error_description: 'Missing sessionId' },
-        {
-          status: 400,
-          headers: {
-            ...CORS_HEADERS,
-          },
-        }
-      );
-    }
-
-    if (!data) {
-      return NextResponse.json(
-        { error_description: "Missing 'data' parameter" },
-        {
-          status: 400,
-          headers: {
-            ...CORS_HEADERS,
-          },
-        }
-      );
-    }
-
-    if (!iv) {
-      return NextResponse.json(
-        { error_description: "Missing 'iv' parameter" },
-        {
-          status: 400,
-          headers: {
-            ...CORS_HEADERS,
-          },
-        }
-      );
-    }
-
-    // Put session data in database
-    await prisma.sessions.upsert({
-      where: {
-        id,
-      },
-      update: {
-        data,
-        iv,
-      },
-      create: {
-        id,
-        data,
-        iv,
-      },
-    });
-
-    return new NextResponse(null, {
-      status: 200,
-      headers: {
-        ...CORS_HEADERS,
-      },
-    });
-  } catch (e) {
-    console.log(e);
-    return NextResponse.json(
-      { error_description: 'Bad request' },
-      {
-        status: 400,
-        headers: {
-          ...CORS_HEADERS,
-        },
-      }
-    );
-  }
-}
-
-export async function OPTIONS() {
-  return new NextResponse(null, {
-    status: 200,
-    headers: {
-      ...CORS_HEADERS,
-    },
-  });
-}
diff --git a/packages/dapp/src/components/AppBottomBar/index.tsx b/packages/dapp/src/components/AppBottomBar/index.tsx
index d69b46491..1e21fe896 100644
--- a/packages/dapp/src/components/AppBottomBar/index.tsx
+++ b/packages/dapp/src/components/AppBottomBar/index.tsx
@@ -33,7 +33,7 @@ const OTHER_LINKS = [
   },
   {
     name: 'qr-scanner',
-    href: '/app/qr-code-session',
+    href: '/app/encrypted-session',
     requiresConnection: false,
   },
 ];
diff --git a/packages/dapp/src/components/ConnectionModal/CreateConnectionModal.tsx b/packages/dapp/src/components/ConnectionModal/CreateConnectionModal.tsx
index 61c16e9c9..1ebb2c66e 100644
--- a/packages/dapp/src/components/ConnectionModal/CreateConnectionModal.tsx
+++ b/packages/dapp/src/components/ConnectionModal/CreateConnectionModal.tsx
@@ -1,11 +1,18 @@
 'use client';
 
 import { useEffect, useState } from 'react';
-import { Modal, ModalBody, ModalContent, ModalHeader } from '@nextui-org/react';
+import {
+  Modal,
+  ModalBody,
+  ModalContent,
+  ModalHeader,
+  Spinner,
+} from '@nextui-org/react';
 import { useTranslations } from 'next-intl';
 import { QRCodeSVG } from 'qrcode.react';
 
-import { useSessionStore } from '@/stores';
+import { useEncryptedSessionStore, useToastStore } from '@/stores';
+import { useAuthStore } from '@/stores/authStore';
 
 interface CreateConnectionModalProps {
   isOpen: boolean;
@@ -17,19 +24,58 @@ const CreateConnectionModal = ({
   setOpen,
 }: CreateConnectionModalProps) => {
   const t = useTranslations('CreateConnectionModal');
+
+  // Local state
   const [connectionData, setConnectionData] = useState<string | null>(null);
-  const { request, session, changeRequest, changeSession } = useSessionStore(
-    (state) => ({
-      request: state.request,
-      session: state.session,
-      changeRequest: state.changeRequest,
-      changeSession: state.changeSession,
-    })
-  );
 
-  const createSession = async (): Promise<string> => {
+  // Global state
+  const { token, isSignedIn } = useAuthStore((state) => ({
+    token: state.token,
+    isSignedIn: state.isSignedIn,
+  }));
+
+  const {
+    changeSession,
+    changeSessionId,
+    changeConnected,
+    changeHasCamera,
+    changeDeviceType,
+  } = useEncryptedSessionStore((state) => ({
+    changeSession: state.changeSession,
+    changeSessionId: state.changeSessionId,
+    changeConnected: state.changeConnected,
+    changeHasCamera: state.changeHasCamera,
+    changeDeviceType: state.changeDeviceType,
+  }));
+
+  const createSession = async (): Promise<string | null> => {
+    if (!token || !isSignedIn) {
+      return null;
+    }
+
     // Create session ID
-    const sessionId = crypto.randomUUID();
+    const createSessionResult = await fetch('/api/encrypted-session', {
+      method: 'GET',
+      headers: {
+        'Content-Type': 'application/json',
+        Authorization: `Bearer ${token}`,
+      },
+    });
+
+    if (!createSessionResult.ok) {
+      setTimeout(() => {
+        useToastStore.setState({
+          open: true,
+          title: t('session-create-failed'),
+          type: 'normal',
+          loading: true,
+          link: null,
+        });
+      }, 200);
+      return null;
+    }
+
+    const { sessionId } = await createSessionResult.json();
 
     const key = await crypto.subtle.generateKey(
       {
@@ -48,13 +94,13 @@ const CreateConnectionModal = ({
 
     // Set global session data
     changeSession({
-      sessionId,
       key,
       exp,
-      connected: false,
-      hasCamera: false,
-      deviceType: 'primary',
     });
+    changeConnected(false);
+    changeHasCamera(false);
+    changeDeviceType('primary');
+    changeSessionId(sessionId);
 
     // Create session
     return JSON.stringify({
@@ -67,12 +113,13 @@ const CreateConnectionModal = ({
   useEffect(() => {
     if (isOpen) {
       createSession()
-        .then((data) => {
-          console.log(data);
-          setConnectionData(data);
-        })
+        .then((data) => setConnectionData(data))
         .catch(console.error);
     }
+
+    return () => {
+      setConnectionData(null);
+    };
   }, [isOpen]);
 
   return (
@@ -106,6 +153,9 @@ const CreateConnectionModal = ({
                       width={300}
                     />
                   )}
+                  {!connectionData && (
+                    <Spinner className="h-[300px] w-[300px]" />
+                  )}
                 </div>
               </div>
             </ModalBody>
diff --git a/packages/dapp/src/components/QRSessionDisplay/ChooseDeviceView.tsx b/packages/dapp/src/components/EncryptedSessionDisplay/ChooseDeviceView.tsx
similarity index 100%
rename from packages/dapp/src/components/QRSessionDisplay/ChooseDeviceView.tsx
rename to packages/dapp/src/components/EncryptedSessionDisplay/ChooseDeviceView.tsx
diff --git a/packages/dapp/src/components/QRSessionDisplay/ConnectDeviceView.tsx b/packages/dapp/src/components/EncryptedSessionDisplay/ConnectDeviceView.tsx
similarity index 65%
rename from packages/dapp/src/components/QRSessionDisplay/ConnectDeviceView.tsx
rename to packages/dapp/src/components/EncryptedSessionDisplay/ConnectDeviceView.tsx
index 2a468e7fc..4d1fc438c 100644
--- a/packages/dapp/src/components/QRSessionDisplay/ConnectDeviceView.tsx
+++ b/packages/dapp/src/components/EncryptedSessionDisplay/ConnectDeviceView.tsx
@@ -1,36 +1,59 @@
 import React, { useEffect, useState } from 'react';
-import { uint8ArrayToHex } from '@blockchain-lab-um/masca-connector';
+import { createClient as createSupbaseClient } from '@supabase/supabase-js';
 import { useTranslations } from 'next-intl';
 import { useAccount } from 'wagmi';
 
 import Button from '@/components/Button';
 import CreateConnectionModal from '@/components/ConnectionModal/CreateConnectionModal';
 import ScanQRCodeModal from '@/components/ScanQRCodeModal/ScanQRCodeModal';
-import { useSessionStore, useToastStore } from '@/stores';
+import { Database } from '@/utils/supabase/database.types';
+import { useEncryptedSessionStore, useToastStore } from '@/stores';
+import { useAuthStore } from '@/stores/authStore';
 
 export const ConnectDeviceView = () => {
   const t = useTranslations('ConnectDeviceView');
+
+  // Local state
+  const [isModalOpen, setIsModalOpen] = useState(false);
+  const [isConnectionModalOpen, setIsConnectionModalOpen] = useState(false);
+
+  // Global state
+  const { isSignedIn, changeIsSignInModalOpen } = useAuthStore((state) => ({
+    isSignedIn: state.isSignedIn,
+    changeIsSignInModalOpen: state.changeIsSignInModalOpen,
+  }));
+
   const { isConnected } = useAccount();
-  const { session, changeSession } = useSessionStore((state) => ({
+  const {
+    connected,
+    deviceType,
+    hasCamera,
+    changeSession,
+    changeConnected,
+    changeSessionId,
+  } = useEncryptedSessionStore((state) => ({
     session: state.session,
+    connected: state.connected,
+    deviceType: state.deviceType,
+    hasCamera: state.hasCamera,
     changeSession: state.changeSession,
+    changeConnected: state.changeConnected,
+    changeSessionId: state.changeSessionId,
   }));
-  const [isModalOpen, setIsModalOpen] = useState(false);
-  const [isConnectionModalOpen, setIsConnectionModalOpen] = useState(false);
 
   useEffect(() => {
     // Close connect QR modal if connection is established
-    if (session.connected && isModalOpen) {
+    if (connected && isModalOpen) {
       setIsModalOpen(false);
     }
-  }, [session.connected]);
+  }, [connected]);
 
   const onScanSuccessConnectionQRCode = async (decodedText: string, _: any) => {
     if (isConnectionModalOpen) {
       setIsConnectionModalOpen(false);
     }
     // Close if already connected
-    if (session.connected) return;
+    if (connected) return;
 
     try {
       const data = JSON.parse(decodedText);
@@ -45,41 +68,27 @@ export const ConnectDeviceView = () => {
         ['encrypt', 'decrypt']
       );
 
-      changeSession({
-        ...session,
-        sessionId: data.sessionId,
-        key: decryptionKey,
-        exp: data.exp,
-        connected: true,
-      });
+      // Send data
+      const client = createSupbaseClient<Database>(
+        process.env.NEXT_PUBLIC_SUPABASE_URL!,
+        process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
+      );
 
-      // Encrypt data
-      const iv = crypto.getRandomValues(new Uint8Array(12));
+      const { error } = await client
+        .from('encrypted_sessions')
+        .update({
+          connected: true,
+        })
+        .eq('id', data.sessionId);
 
-      const encodedText = new TextEncoder().encode('Created Connection');
+      if (error) throw new Error('Failed to send data');
 
-      const encryptedData = new Uint8Array(
-        await crypto.subtle.encrypt(
-          {
-            name: 'AES-GCM',
-            iv,
-          },
-          decryptionKey,
-          encodedText
-        )
-      );
-      const response = await fetch(`/api/qr-code-session/${data.sessionId}`, {
-        method: 'POST',
-        headers: {
-          'Content-Type': 'application/json',
-        },
-        body: JSON.stringify({
-          data: uint8ArrayToHex(encryptedData),
-          iv: uint8ArrayToHex(iv),
-        }),
+      changeSession({
+        key: decryptionKey,
+        exp: data.exp,
       });
-
-      if (!response.ok) throw new Error();
+      changeConnected(true);
+      changeSessionId(data.sessionId);
 
       setTimeout(() => {
         useToastStore.setState({
@@ -91,6 +100,7 @@ export const ConnectDeviceView = () => {
         });
       }, 200);
     } catch (e) {
+      console.log(e);
       setTimeout(() => {
         useToastStore.setState({
           open: true,
@@ -105,7 +115,7 @@ export const ConnectDeviceView = () => {
 
   return (
     <div className="">
-      {session.deviceType === 'primary' && !session.hasCamera && (
+      {deviceType === 'primary' && !hasCamera && (
         <>
           {isConnected && (
             <>
@@ -117,7 +127,16 @@ export const ConnectDeviceView = () => {
                 </div>
               </div>
               <div className="mt-8 flex justify-center">
-                <Button variant="primary" onClick={() => setIsModalOpen(true)}>
+                <Button
+                  variant="primary"
+                  onClick={() => {
+                    if (!isSignedIn) {
+                      changeIsSignInModalOpen(true);
+                      return;
+                    }
+                    setIsModalOpen(true);
+                  }}
+                >
                   {t('create')}
                 </Button>
               </div>
@@ -126,9 +145,9 @@ export const ConnectDeviceView = () => {
           {!isConnected && <div>{t('connect')}</div>}
         </>
       )}
-      {session.hasCamera && (
+      {hasCamera && (
         <>
-          {session.deviceType === 'secondary' && (
+          {deviceType === 'secondary' && (
             <>
               <div className="dark:bg-navy-blue-700 rounded-xl bg-gray-100 p-4">
                 <div>{t('start-secondary')}</div>
@@ -138,13 +157,12 @@ export const ConnectDeviceView = () => {
                   variant="primary"
                   onClick={() => {
                     // Reset session if already set
+                    changeSessionId(null);
                     changeSession({
-                      ...session,
-                      sessionId: null,
                       key: null,
                       exp: null,
-                      connected: false,
                     });
+                    changeConnected(false);
                     setIsConnectionModalOpen(true);
                   }}
                 >
diff --git a/packages/dapp/src/components/QRSessionDisplay/CredentialView.tsx b/packages/dapp/src/components/EncryptedSessionDisplay/CredentialView.tsx
similarity index 95%
rename from packages/dapp/src/components/QRSessionDisplay/CredentialView.tsx
rename to packages/dapp/src/components/EncryptedSessionDisplay/CredentialView.tsx
index 44e1aadcd..6d6d98bfe 100644
--- a/packages/dapp/src/components/QRSessionDisplay/CredentialView.tsx
+++ b/packages/dapp/src/components/EncryptedSessionDisplay/CredentialView.tsx
@@ -8,7 +8,11 @@ import { useTranslations } from 'next-intl';
 import Button from '@/components/Button';
 import FormatedPanel from '@/components/CredentialDisplay/FormatedPanel';
 import JsonPanel from '@/components/CredentialDisplay/JsonPanel';
-import { useMascaStore, useSessionStore, useToastStore } from '@/stores';
+import {
+  useEncryptedSessionStore,
+  useMascaStore,
+  useToastStore,
+} from '@/stores';
 
 interface CredentialViewProps {
   credential: VerifiableCredential;
@@ -20,7 +24,9 @@ export const CredentialView = ({
   scanNewCode,
 }: CredentialViewProps) => {
   const t = useTranslations('CredentialView');
-  const changeRequest = useSessionStore((state) => state.changeRequest);
+  const changeRequest = useEncryptedSessionStore(
+    (state) => state.changeRequest
+  );
 
   const mascaApi = useMascaStore((state) => state.mascaApi);
 
diff --git a/packages/dapp/src/components/QRSessionDisplay/ScanQRCodeView.tsx b/packages/dapp/src/components/EncryptedSessionDisplay/ScanQRCodeView.tsx
similarity index 79%
rename from packages/dapp/src/components/QRSessionDisplay/ScanQRCodeView.tsx
rename to packages/dapp/src/components/EncryptedSessionDisplay/ScanQRCodeView.tsx
index a166944b0..a70454187 100644
--- a/packages/dapp/src/components/QRSessionDisplay/ScanQRCodeView.tsx
+++ b/packages/dapp/src/components/EncryptedSessionDisplay/ScanQRCodeView.tsx
@@ -1,5 +1,6 @@
 import React, { useState } from 'react';
 import { uint8ArrayToHex } from '@blockchain-lab-um/masca-connector';
+import { createClient as createSupbaseClient } from '@supabase/supabase-js';
 import { Html5Qrcode } from 'html5-qrcode';
 import { useTranslations } from 'next-intl';
 import { useAccount } from 'wagmi';
@@ -7,7 +8,9 @@ import { useAccount } from 'wagmi';
 import Button from '@/components/Button';
 import ScanQRCodeModal from '@/components/ScanQRCodeModal/ScanQRCodeModal';
 import UploadButton from '@/components/UploadButton';
-import { useSessionStore, useToastStore } from '@/stores';
+import { Database } from '@/utils/supabase/database.types';
+import { useToastStore } from '@/stores';
+import { useEncryptedSessionStore } from '@/stores/encryptedSessionStore';
 import { useQRCodeStore } from '@/stores/qrCodeStore';
 
 interface ScanQRCodeViewProps {
@@ -18,22 +21,27 @@ export const ScanQRCodeView = ({ onQRCodeScanned }: ScanQRCodeViewProps) => {
   const t = useTranslations('ScanQRCodeView');
   const { isConnected } = useAccount();
   const [isQRCodeModalOpen, setIsQRCodeModalOpen] = useState(false);
+  const { sessionId, session, deviceType, hasCamera, isSessionConnect } =
+    useEncryptedSessionStore((state) => ({
+      sessionId: state.sessionId,
+      session: state.session,
+      deviceType: state.deviceType,
+      hasCamera: state.hasCamera,
+      isSessionConnect: state.connected,
+    }));
 
-  const session = useSessionStore((state) => state.session);
-
-  const changeRequestData = useQRCodeStore((state) => state.changeRequestData);
+  const changeRequestData = useQRCodeStore((state) => state.changeRequestData); // TODO: Where was this used
 
   const onScanSuccessQRCode = async (decodedText: string, _: any) => {
     // Same device
-    if (isConnected && session.deviceType === 'primary') {
+    if (isConnected && deviceType === 'primary') {
       changeRequestData(decodedText);
       return;
     }
 
     // Cross device (mobile <-> desktop)
-    if (!session.sessionId || !session.key || !session.exp) return;
+    if (!sessionId || !session.key || !session.exp) return;
     if (isQRCodeModalOpen) {
-      console.log('Closing QR Scan modal...');
       setIsQRCodeModalOpen(false);
     }
     let data: string | null = null;
@@ -82,34 +90,21 @@ export const ScanQRCodeView = ({ onQRCodeScanned }: ScanQRCodeViewProps) => {
       );
 
       // Send data
-      const response = await fetch(
-        `/api/qr-code-session/${session.sessionId}`,
-        {
-          method: 'POST',
-          headers: {
-            'Content-Type': 'application/json',
-          },
-          body: JSON.stringify({
-            data: uint8ArrayToHex(encryptedData),
-            iv: uint8ArrayToHex(iv),
-          }),
-        }
+      const client = createSupbaseClient<Database>(
+        process.env.NEXT_PUBLIC_SUPABASE_URL!,
+        process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
       );
 
-      if (!response.ok) throw new Error();
+      const { error } = await client
+        .from('encrypted_sessions')
+        .update({
+          data: uint8ArrayToHex(encryptedData),
+          iv: uint8ArrayToHex(iv),
+        })
+        .eq('id', sessionId);
 
-      setTimeout(() => {
-        useToastStore.setState({
-          open: true,
-          title: t('success'),
-          type: 'success',
-          loading: false,
-          link: null,
-        });
-      }, 200);
-      onQRCodeScanned();
+      if (error) throw new Error('Failed to send data');
     } catch (e) {
-      console.log('error', e);
       setTimeout(() => {
         useToastStore.setState({
           open: true,
@@ -147,9 +142,9 @@ export const ScanQRCodeView = ({ onQRCodeScanned }: ScanQRCodeViewProps) => {
 
   return (
     <div>
-      {session.connected && (
+      {isSessionConnect && (
         <>
-          {session.deviceType === 'primary' && session.hasCamera && (
+          {deviceType === 'primary' && hasCamera && (
             <div>
               <div className="dark:bg-navy-blue-700 rounded-xl bg-gray-100 p-4">
                 {t('scan-upload')}
@@ -166,7 +161,7 @@ export const ScanQRCodeView = ({ onQRCodeScanned }: ScanQRCodeViewProps) => {
               </div>
             </div>
           )}
-          {session.deviceType === 'secondary' && session.hasCamera && (
+          {deviceType === 'secondary' && hasCamera && (
             <div>
               <div className="dark:bg-navy-blue-700 rounded-xl bg-gray-100 p-4">
                 <div>
@@ -189,7 +184,7 @@ export const ScanQRCodeView = ({ onQRCodeScanned }: ScanQRCodeViewProps) => {
           )}
         </>
       )}
-      {session.connected && !session.hasCamera && (
+      {isSessionConnect && !hasCamera && (
         <>
           <div>
             <div className="dark:bg-navy-blue-700 rounded-xl bg-gray-100 p-4">
diff --git a/packages/dapp/src/components/QRSessionDisplay/StartFlowView/CredentialOfferView.tsx b/packages/dapp/src/components/EncryptedSessionDisplay/StartFlowView/CredentialOfferView.tsx
similarity index 95%
rename from packages/dapp/src/components/QRSessionDisplay/StartFlowView/CredentialOfferView.tsx
rename to packages/dapp/src/components/EncryptedSessionDisplay/StartFlowView/CredentialOfferView.tsx
index deda0e345..e18e8d9f5 100644
--- a/packages/dapp/src/components/QRSessionDisplay/StartFlowView/CredentialOfferView.tsx
+++ b/packages/dapp/src/components/EncryptedSessionDisplay/StartFlowView/CredentialOfferView.tsx
@@ -5,7 +5,11 @@ import { useTranslations } from 'next-intl';
 import { useAccount } from 'wagmi';
 
 import Button from '@/components/Button';
-import { useMascaStore, useSessionStore, useToastStore } from '@/stores';
+import {
+  useEncryptedSessionStore,
+  useMascaStore,
+  useToastStore,
+} from '@/stores';
 
 interface CredentialOfferViewProps {
   onCredentialRecieved: (recievedCredential: VerifiableCredential) => void;
@@ -15,7 +19,7 @@ export const CredentialOfferView = ({
   onCredentialRecieved,
 }: CredentialOfferViewProps) => {
   const t = useTranslations('CredentialOfferView');
-  const { request, changeRequest } = useSessionStore((state) => ({
+  const { request, changeRequest } = useEncryptedSessionStore((state) => ({
     request: state.request,
     changeRequest: state.changeRequest,
   }));
diff --git a/packages/dapp/src/components/QRSessionDisplay/StartFlowView/OIDCAuthView.tsx b/packages/dapp/src/components/EncryptedSessionDisplay/StartFlowView/OIDCAuthView.tsx
similarity index 94%
rename from packages/dapp/src/components/QRSessionDisplay/StartFlowView/OIDCAuthView.tsx
rename to packages/dapp/src/components/EncryptedSessionDisplay/StartFlowView/OIDCAuthView.tsx
index 3f248cc2c..0c7deb053 100644
--- a/packages/dapp/src/components/QRSessionDisplay/StartFlowView/OIDCAuthView.tsx
+++ b/packages/dapp/src/components/EncryptedSessionDisplay/StartFlowView/OIDCAuthView.tsx
@@ -4,7 +4,11 @@ import { useTranslations } from 'next-intl';
 import { useAccount } from 'wagmi';
 
 import Button from '@/components/Button';
-import { useMascaStore, useSessionStore, useToastStore } from '@/stores';
+import {
+  useEncryptedSessionStore,
+  useMascaStore,
+  useToastStore,
+} from '@/stores';
 
 interface OIDCAuthViewProps {
   scanNewCode: () => void;
@@ -12,7 +16,7 @@ interface OIDCAuthViewProps {
 
 export const OIDCAuthView = ({ scanNewCode }: OIDCAuthViewProps) => {
   const t = useTranslations('OIDCAuthView');
-  const { request, changeRequest } = useSessionStore((state) => ({
+  const { request, changeRequest } = useEncryptedSessionStore((state) => ({
     request: state.request,
     changeRequest: state.changeRequest,
   }));
diff --git a/packages/dapp/src/components/QRSessionDisplay/StartFlowView/PolygonAuthView.tsx b/packages/dapp/src/components/EncryptedSessionDisplay/StartFlowView/PolygonAuthView.tsx
similarity index 94%
rename from packages/dapp/src/components/QRSessionDisplay/StartFlowView/PolygonAuthView.tsx
rename to packages/dapp/src/components/EncryptedSessionDisplay/StartFlowView/PolygonAuthView.tsx
index 56e66a2e6..e44b67ec2 100644
--- a/packages/dapp/src/components/QRSessionDisplay/StartFlowView/PolygonAuthView.tsx
+++ b/packages/dapp/src/components/EncryptedSessionDisplay/StartFlowView/PolygonAuthView.tsx
@@ -4,7 +4,11 @@ import { useTranslations } from 'next-intl';
 import { useAccount } from 'wagmi';
 
 import Button from '@/components/Button';
-import { useMascaStore, useSessionStore, useToastStore } from '@/stores';
+import {
+  useEncryptedSessionStore,
+  useMascaStore,
+  useToastStore,
+} from '@/stores';
 
 interface StartFlowViewProps {
   scanNewCode: () => void;
@@ -12,7 +16,7 @@ interface StartFlowViewProps {
 
 export const PolygonAuthView = ({ scanNewCode }: StartFlowViewProps) => {
   const t = useTranslations('PolygonAuthView');
-  const { request, changeRequest } = useSessionStore((state) => ({
+  const { request, changeRequest } = useEncryptedSessionStore((state) => ({
     request: state.request,
     session: state.session,
     changeRequest: state.changeRequest,
diff --git a/packages/dapp/src/components/QRSessionDisplay/StartFlowView/index.tsx b/packages/dapp/src/components/EncryptedSessionDisplay/StartFlowView/index.tsx
similarity index 86%
rename from packages/dapp/src/components/QRSessionDisplay/StartFlowView/index.tsx
rename to packages/dapp/src/components/EncryptedSessionDisplay/StartFlowView/index.tsx
index 487e982ea..ed9578dbd 100644
--- a/packages/dapp/src/components/QRSessionDisplay/StartFlowView/index.tsx
+++ b/packages/dapp/src/components/EncryptedSessionDisplay/StartFlowView/index.tsx
@@ -4,7 +4,7 @@ import { useTranslations } from 'next-intl';
 import { useAccount } from 'wagmi';
 
 import Button from '@/components/Button';
-import { useSessionStore } from '@/stores';
+import { useEncryptedSessionStore } from '@/stores';
 import { CredentialOfferView } from './CredentialOfferView';
 import { OIDCAuthView } from './OIDCAuthView';
 import { PolygonAuthView } from './PolygonAuthView';
@@ -19,16 +19,16 @@ export const StartFlowView = ({
   onCredentialRecieved,
 }: StartFlowViewProps) => {
   const t = useTranslations('StartFlowView');
-  const { request, session } = useSessionStore((state) => ({
+  const { request, deviceType } = useEncryptedSessionStore((state) => ({
     request: state.request,
-    session: state.session,
+    deviceType: state.deviceType,
   }));
 
   const { isConnected } = useAccount();
 
   return (
     <div>
-      {isConnected && session.deviceType === 'primary' && (
+      {isConnected && deviceType === 'primary' && (
         <>
           {request.type === 'polygonAuth' && (
             <PolygonAuthView scanNewCode={scanNewCode} />
@@ -42,7 +42,7 @@ export const StartFlowView = ({
           )}
         </>
       )}
-      {session.deviceType === 'secondary' && (
+      {deviceType === 'secondary' && (
         <>
           <div className="dark:bg-navy-blue-700 rounded-xl bg-gray-100 p-4">
             {t('scanned')}
diff --git a/packages/dapp/src/components/QRSessionDisplay/index.tsx b/packages/dapp/src/components/EncryptedSessionDisplay/index.tsx
similarity index 85%
rename from packages/dapp/src/components/QRSessionDisplay/index.tsx
rename to packages/dapp/src/components/EncryptedSessionDisplay/index.tsx
index 59086ec07..f32d8ac98 100644
--- a/packages/dapp/src/components/QRSessionDisplay/index.tsx
+++ b/packages/dapp/src/components/EncryptedSessionDisplay/index.tsx
@@ -9,15 +9,15 @@ import { useTranslations } from 'next-intl';
 import { useAccount } from 'wagmi';
 
 import Button from '@/components/Button';
-import { useSessionStore } from '@/stores';
+import { useEncryptedSessionStore } from '@/stores/encryptedSessionStore';
 import { ChooseDeviceView } from './ChooseDeviceView';
 import { ConnectDeviceView } from './ConnectDeviceView';
 import { CredentialView } from './CredentialView';
 import { ScanQRCodeView } from './ScanQRCodeView';
 import { StartFlowView } from './StartFlowView';
 
-const QRSessionDisplay = () => {
-  const t = useTranslations('QRSessionDisplay');
+const EncryptedSessionDisplay = () => {
+  const t = useTranslations('EncryptedSessionDisplay');
   const steps = useMemo(
     () => [
       {
@@ -48,20 +48,36 @@ const QRSessionDisplay = () => {
   const stepperInstance = useStepper({ steps });
   const { isConnected } = useAccount();
 
-  const { request, session, changeRequest, changeSession } = useSessionStore(
-    (state) => ({
-      request: state.request,
-      session: state.session,
-      changeRequest: state.changeRequest,
-      changeSession: state.changeSession,
-    })
-  );
+  const {
+    request,
+    session,
+
+    deviceType,
+    hasCamera,
+    connected,
+    changeRequest,
+    changeSession,
+    changeConnected,
+    changeDeviceType,
+    changeHasCamera,
+  } = useEncryptedSessionStore((state) => ({
+    request: state.request,
+    session: state.session,
+    deviceType: state.deviceType,
+    hasCamera: state.hasCamera,
+    connected: state.connected,
+    changeRequest: state.changeRequest,
+    changeSession: state.changeSession,
+    changeConnected: state.changeConnected,
+    changeDeviceType: state.changeDeviceType,
+    changeHasCamera: state.changeHasCamera,
+  }));
 
   useEffect(() => {
-    if (session.connected && stepperInstance.state.currentStep === 1) {
+    if (connected && stepperInstance.state.currentStep === 1) {
       stepperInstance.setStep(2);
     }
-  }, [session.connected]);
+  }, [connected]);
 
   useEffect(() => {
     if (
@@ -77,11 +93,11 @@ const QRSessionDisplay = () => {
   }, [request]);
 
   useEffect(() => {
-    if (session.deviceType === null) {
+    if (deviceType === null) {
       stepperInstance.setStep(0);
       return;
     }
-    if (session.connected && session.exp && session.exp > Date.now()) {
+    if (connected && session.exp && session.exp > Date.now()) {
       stepperInstance.setStep(2);
       if (request.active) {
         stepperInstance.setStep(3);
@@ -101,27 +117,21 @@ const QRSessionDisplay = () => {
   };
 
   const onDeviceTypeSelected = (
-    deviceType: 'primary' | 'secondary',
-    hasCamera: boolean
+    _deviceType: 'primary' | 'secondary',
+    _hasCamera: boolean
   ) => {
-    if (deviceType === 'primary' && hasCamera) {
+    if (_deviceType === 'primary' && _hasCamera) {
       changeSession({
-        connected: true,
-        sessionId: null,
         key: null,
         exp: null,
-        deviceType,
-        hasCamera,
       });
-
+      changeConnected(true);
+      changeDeviceType(_deviceType);
+      changeHasCamera(_hasCamera);
       stepperInstance.setStep(2);
     } else {
-      changeSession({
-        ...session,
-        deviceType,
-        hasCamera,
-      });
-
+      changeDeviceType(_deviceType);
+      changeHasCamera(_hasCamera);
       stepperInstance.nextStep();
     }
   };
@@ -216,7 +226,7 @@ const QRSessionDisplay = () => {
       {steps[stepperInstance.state.currentStep].hasPreviousStep && (
         <div className="mt-4 flex justify-end">
           {stepperInstance.state.currentStep === 1 &&
-            session.connected &&
+            connected &&
             session.exp &&
             session.exp > Date.now() && (
               <div className="mr-2">
@@ -257,4 +267,4 @@ const QRSessionDisplay = () => {
   );
 };
 
-export default QRSessionDisplay;
+export default EncryptedSessionDisplay;
diff --git a/packages/dapp/src/components/EncryptedSessionProvider/index.tsx b/packages/dapp/src/components/EncryptedSessionProvider/index.tsx
new file mode 100644
index 000000000..ede1b146e
--- /dev/null
+++ b/packages/dapp/src/components/EncryptedSessionProvider/index.tsx
@@ -0,0 +1,202 @@
+'use client';
+
+import { useEffect, useMemo } from 'react';
+import { hexToUint8Array } from '@blockchain-lab-um/masca-connector';
+import { useTranslations } from 'next-intl';
+import { useAccount } from 'wagmi';
+
+import { createClient } from '@/utils/supabase/client';
+import { useMascaStore, useToastStore } from '@/stores';
+import { useAuthStore } from '@/stores/authStore';
+import { useEncryptedSessionStore } from '@/stores/encryptedSessionStore';
+
+export const EncryptedSessionProvider = () => {
+  const t = useTranslations('EncryptedSessionProvider');
+  const token = useAuthStore((state) => state.token);
+
+  const { address } = useAccount();
+
+  const {
+    sessionId,
+    session,
+    request,
+    deviceType,
+    changeConnected,
+    changeRequest,
+    changeSession,
+  } = useEncryptedSessionStore((state) => ({
+    sessionId: state.sessionId,
+    session: state.session,
+    request: state.request,
+    deviceType: state.deviceType,
+    changeConnected: state.changeConnected,
+    changeRequest: state.changeRequest,
+    changeSession: state.changeSession,
+  }));
+
+  const api = useMascaStore((state) => state.mascaApi);
+
+  const client = useMemo(() => createClient(token ?? ''), [token]);
+
+  // Decrypt data
+  const decryptData = async ({
+    iv,
+    encryptedData,
+  }: {
+    iv: Uint8Array;
+    encryptedData: string;
+  }) => {
+    const decrypted = await crypto.subtle.decrypt(
+      {
+        name: 'AES-GCM',
+        iv,
+      },
+      session.key!,
+      hexToUint8Array(encryptedData)
+    );
+
+    const decoded = new TextDecoder().decode(decrypted);
+
+    return decoded;
+  };
+
+  const handleRequest = async (data: string) => {
+    if (!api) return;
+    if (request.active) return;
+
+    // OIDC Credential Offer
+    if (data.startsWith('openid-credential-offer://')) {
+      changeRequest({
+        active: true,
+        data,
+        type: 'credentialOffer',
+        finished: false,
+      });
+
+      return;
+    }
+
+    // OIDC Authorization Request
+    if (data.startsWith('openid://')) {
+      changeRequest({
+        active: true,
+        data,
+        type: 'oidcAuth',
+        finished: false,
+      });
+      return;
+    }
+
+    let jsonDecodedData;
+    try {
+      jsonDecodedData = JSON.parse(data);
+      if (!jsonDecodedData) throw new Error('Invalid JSON');
+
+      // Polygon Credential Offer
+      if (
+        jsonDecodedData.type ===
+        'https://iden3-communication.io/credentials/1.0/offer'
+      ) {
+        changeRequest({
+          active: true,
+          data,
+          type: 'polygonCredentialOffer',
+          finished: false,
+        });
+        return;
+      }
+
+      // Polygon Authorization Request
+      if (
+        jsonDecodedData.type ===
+        'https://iden3-communication.io/authorization/1.0/request'
+      ) {
+        changeRequest({
+          active: true,
+          data,
+          type: 'polygonAuth',
+          finished: false,
+        });
+
+        return;
+      }
+    } catch (e) {
+      console.log(e);
+    }
+
+    setTimeout(() => {
+      useToastStore.setState({
+        open: true,
+        title: t('unsuported'),
+        type: 'error',
+        loading: false,
+        link: null,
+      });
+    }, 200);
+  };
+
+  useEffect(() => {
+    if (sessionId && deviceType === 'primary') {
+      client
+        .channel('realtime encrypted_sessions')
+        .on(
+          'postgres_changes',
+          { event: 'UPDATE', schema: 'public', table: 'encrypted_sessions' },
+          async () => {
+            const { data, error } = await client
+              .from('encrypted_sessions')
+              .select()
+              .eq('id', sessionId)
+              .single();
+
+            if (error || !data) {
+              useToastStore.setState({
+                open: true,
+                title: t('fetch-failed'),
+                type: 'error',
+                loading: false,
+                link: null,
+              });
+
+              return;
+            }
+
+            if (data.connected) {
+              changeConnected(true);
+            }
+
+            if (!data.data || !data.iv) return;
+
+            const decryptedData = await decryptData({
+              iv: hexToUint8Array(data.iv),
+              encryptedData: data.data,
+            });
+
+            await handleRequest(decryptedData);
+          }
+        )
+        .subscribe();
+    }
+  }, [sessionId]);
+
+  useEffect(() => {
+    if (!session.exp) return;
+
+    if (session.exp && session.exp < Date.now()) {
+      changeSession({
+        key: null,
+        exp: null,
+      });
+    }
+  }, [session.exp]);
+
+  useEffect(() => {
+    changeConnected(false);
+    changeSession({
+      exp: null,
+      key: null,
+    });
+  }, [address]);
+
+  return null;
+};
diff --git a/packages/dapp/src/components/MenuPopover/index.tsx b/packages/dapp/src/components/MenuPopover/index.tsx
index cf0ca5a01..1cad70080 100644
--- a/packages/dapp/src/components/MenuPopover/index.tsx
+++ b/packages/dapp/src/components/MenuPopover/index.tsx
@@ -87,7 +87,7 @@ const INTERNAL_LINKS: LinkProps[] = [
   },
   {
     name: 'qr-scanner',
-    href: '/app/qr-code-session',
+    href: '/app/encrypted-session',
     icon: IconCamera,
     requiresConnection: false,
   },
diff --git a/packages/dapp/src/components/QRCodeSessionProvider/index.tsx b/packages/dapp/src/components/QRCodeSessionProvider/index.tsx
deleted file mode 100644
index 3a14feb21..000000000
--- a/packages/dapp/src/components/QRCodeSessionProvider/index.tsx
+++ /dev/null
@@ -1,193 +0,0 @@
-'use client';
-
-import { useEffect } from 'react';
-import { hexToUint8Array } from '@blockchain-lab-um/masca-connector';
-import { useTranslations } from 'next-intl';
-import useSWR from 'swr';
-import { useAccount } from 'wagmi';
-
-import { useMascaStore, useSessionStore, useToastStore } from '@/stores';
-import { useQRCodeStore } from '@/stores/qrCodeStore';
-
-const fetcher = (url: string) => fetch(url).then((r) => r.json());
-
-const QRCodeSessionProvider = () => {
-  const t = useTranslations('QRCodeSessionProvider');
-
-  const { request, session, changeRequest } = useSessionStore((state) => ({
-    request: state.request,
-    session: state.session,
-    changeRequest: state.changeRequest,
-    changeSession: state.changeSession,
-  }));
-
-  const requestData = useQRCodeStore((state) => state.requestData);
-  const { isConnected } = useAccount();
-  const api = useMascaStore((state) => state.mascaApi);
-
-  // Conditionally fetch session data
-  const { data } = useSWR(
-    () =>
-      session.sessionId && isConnected
-        ? `/api/qr-code-session/${session.sessionId}`
-        : null,
-    fetcher,
-    {
-      // Refresh every 10 seconds
-      errorRetryInterval: 10000,
-      errorRetryCount: 100,
-      refreshInterval: 10000,
-    }
-  );
-
-  useEffect(() => {
-    if (!session.exp) return;
-
-    if (session.exp && session.exp < Date.now()) {
-      useSessionStore.setState({
-        session: {
-          sessionId: null,
-          key: null,
-          exp: null,
-          connected: false,
-          deviceType: null,
-          hasCamera: false,
-        },
-      });
-    }
-  }, [session.exp]);
-
-  const handleNewRequest = async (_data: string) => {
-    if (_data === 'Created Connection') {
-      useSessionStore.setState({
-        session: { ...session, connected: true },
-      });
-      return;
-    }
-    if (!isConnected) return;
-    if (!api) return;
-    if (request.active) return;
-
-    // OIDC Credential Offer
-    if (_data.startsWith('openid-credential-offer://')) {
-      changeRequest({
-        active: true,
-        data: _data,
-        type: 'credentialOffer',
-        finished: false,
-      });
-
-      return;
-    }
-
-    // OIDC Authorization Request
-    if (_data.startsWith('openid://')) {
-      changeRequest({
-        active: true,
-        data: _data,
-        type: 'oidcAuth',
-        finished: false,
-      });
-      return;
-    }
-
-    let jsonDecodedData;
-    try {
-      jsonDecodedData = JSON.parse(_data);
-      if (!jsonDecodedData) throw new Error('Invalid JSON');
-
-      // Polygon Credential Offer
-      if (
-        jsonDecodedData.type ===
-        'https://iden3-communication.io/credentials/1.0/offer'
-      ) {
-        changeRequest({
-          active: true,
-          data: _data,
-          type: 'polygonCredentialOffer',
-          finished: false,
-        });
-        return;
-      }
-
-      // Polygon Authorization Request
-      if (
-        jsonDecodedData.type ===
-        'https://iden3-communication.io/authorization/1.0/request'
-      ) {
-        setTimeout(() => {
-          useToastStore.setState({
-            open: true,
-            title: 'Polygon Authorization Request received',
-            type: 'info',
-            loading: false,
-            link: `/app/qr-code-session`,
-          });
-        }, 200);
-
-        changeRequest({
-          active: true,
-          data: _data,
-          type: 'polygonAuth',
-          finished: false,
-        });
-
-        return;
-      }
-    } catch (e) {
-      console.log(e);
-    }
-
-    setTimeout(() => {
-      useToastStore.setState({
-        open: true,
-        title: t('unsuported'),
-        type: 'error',
-        loading: false,
-        link: null,
-      });
-    }, 200);
-  };
-
-  // Decrypt received data
-  useEffect(() => {
-    if (!session.key || !data) return;
-
-    const { data: encryptedData, iv: encodedIV } = data;
-
-    if (data.error_descrition || !encryptedData || !encodedIV) return;
-
-    // Data to uint8array
-    const iv = hexToUint8Array(encodedIV);
-
-    // Decrypt data
-    const decryptData = async () => {
-      const decrypted = await crypto.subtle.decrypt(
-        {
-          name: 'AES-GCM',
-          iv,
-        },
-        session.key!,
-        hexToUint8Array(encryptedData)
-      );
-
-      const decoded = new TextDecoder().decode(decrypted);
-
-      return decoded;
-    };
-
-    decryptData()
-      .then(async (_data) => handleNewRequest(_data))
-      .catch((e) => console.log(e));
-  }, [data, session.key]);
-
-  // New request recieved (QR Code upload)
-  useEffect(() => {
-    if (!requestData) return;
-    handleNewRequest(requestData).catch((e) => console.log(e));
-  }, [requestData]);
-
-  return null;
-};
-
-export default QRCodeSessionProvider;
diff --git a/packages/dapp/src/messages/en.json b/packages/dapp/src/messages/en.json
index b918fa0d2..bdf0335bd 100644
--- a/packages/dapp/src/messages/en.json
+++ b/packages/dapp/src/messages/en.json
@@ -24,7 +24,7 @@
         "create-credential": "Create a custom credential",
         "documentation": "Read the Masca documentation",
         "get-credential": "Get your credential using the OpenID Connect protocol",
-        "qr-code-session": "Create session to scan QR codes using your mobile device",
+        "qr-code-session": "Create an encrypted session to scan QR codes using your mobile device",
         "qr-scanner": "Receive credentials and share presentations by scanning QR codes",
         "shared-presentations": "Check your shared presentations",
         "verify-data": "Verify credentials & presentations"
@@ -123,7 +123,8 @@
   },
   "CreateConnectionModal": {
     "desc": " Scan this QR code with your mobile device to create a connection to this page.",
-    "title": "Connection QR Code"
+    "title": "Connection QR Code",
+    "session-create-failed": "Failed to create session. Please try again."
   },
   "CreateCredentialDisplay": {
     "invalidMethod": "Polygon ID & Iden3 are not yet supported. Switch to any other DID method to create a credential!",
@@ -447,10 +448,11 @@
     "qr-invalid-error": "Invalid QR code",
     "starting-error": "Failed to start QR code scanner"
   },
-  "QRCodeSessionProvider": {
-    "unsuported": "Unsuported QR code data received"
+  "EncryptedSessionProvider": {
+    "unsuported": "Unsuported QR code data received",
+    "fetch-failed": "Failed to fetch session. Please try again."
   },
-  "QRSessionDisplay": {
+  "EncryptedSessionDisplay": {
     "back": "Back",
     "fifth": "Fifth Step",
     "fifth-desc": "Finish Flow",
diff --git a/packages/dapp/src/stores/encryptedSessionStore.ts b/packages/dapp/src/stores/encryptedSessionStore.ts
new file mode 100644
index 000000000..5ffbc2fac
--- /dev/null
+++ b/packages/dapp/src/stores/encryptedSessionStore.ts
@@ -0,0 +1,67 @@
+import { shallow } from 'zustand/shallow';
+import { createWithEqualityFn } from 'zustand/traditional';
+
+interface EncryptedRequest {
+  type:
+    | 'polygonAuth'
+    | 'oidcAuth'
+    | 'credentialOffer'
+    | 'polygonCredentialOffer'
+    | null;
+  data: string | null;
+  active: boolean;
+  finished: boolean;
+}
+
+interface Session {
+  key: CryptoKey | null;
+  exp: number | null;
+}
+
+interface EncryptedSessionStore {
+  sessionId: string | null;
+  request: EncryptedRequest;
+  session: Session;
+  connected: boolean;
+  deviceType: 'primary' | 'secondary' | null;
+  hasCamera: boolean;
+
+  changeSessionId: (sessionId: string | null) => void;
+  changeRequest: (request: EncryptedRequest) => void;
+  changeSession: (session: Session) => void;
+  changeConnected: (connected: boolean) => void;
+  changeDeviceType: (deviceType: 'primary' | 'secondary') => void;
+  changeHasCamera: (hasCamera: boolean) => void;
+}
+
+export const encryptedSessionInitialState = {
+  sessionId: null,
+  request: {
+    type: null,
+    data: null,
+    active: false,
+    finished: false,
+  },
+  session: {
+    key: null,
+    exp: null,
+  },
+  connected: false,
+  deviceType: null,
+  hasCamera: false,
+};
+
+export const useEncryptedSessionStore =
+  createWithEqualityFn<EncryptedSessionStore>()(
+    (set) => ({
+      ...encryptedSessionInitialState,
+      changeSessionId: (sessionId: string | null) => set({ sessionId }),
+      changeRequest: (request: EncryptedRequest) => set({ request }),
+      changeSession: (session: Session) => set({ session }),
+      changeConnected: (connected: boolean) => set({ connected }),
+      changeDeviceType: (deviceType: 'primary' | 'secondary') =>
+        set({ deviceType }),
+      changeHasCamera: (hasCamera: boolean) => set({ hasCamera }),
+    }),
+    shallow
+  );
diff --git a/packages/dapp/src/stores/index.ts b/packages/dapp/src/stores/index.ts
index cbac77b12..06b1a1d82 100644
--- a/packages/dapp/src/stores/index.ts
+++ b/packages/dapp/src/stores/index.ts
@@ -2,4 +2,4 @@ export * from './generalStore';
 export * from './snapStore';
 export * from './tableStore';
 export * from './toastStore';
-export * from './sessionStore';
+export * from './encryptedSessionStore';
diff --git a/packages/dapp/src/stores/sessionStore.ts b/packages/dapp/src/stores/sessionStore.ts
deleted file mode 100644
index 2abab74bf..000000000
--- a/packages/dapp/src/stores/sessionStore.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { shallow } from 'zustand/shallow';
-import { createWithEqualityFn } from 'zustand/traditional';
-
-interface QRRequest {
-  type:
-    | 'polygonAuth'
-    | 'oidcAuth'
-    | 'credentialOffer'
-    | 'polygonCredentialOffer'
-    | null;
-  data: string | null;
-  active: boolean;
-  finished: boolean;
-}
-
-interface Session {
-  sessionId: string | null;
-  key: CryptoKey | null;
-  exp: number | null;
-  connected: boolean;
-  deviceType: 'primary' | 'secondary' | null;
-  hasCamera: boolean;
-}
-
-interface SessionStore {
-  request: QRRequest;
-  session: Session;
-  changeRequest: (request: QRRequest) => void;
-  changeSession: (session: Session) => void;
-}
-
-export const sessionStoreInitialState = {
-  request: {
-    type: null,
-    data: null,
-    active: false,
-    finished: false,
-  },
-  session: {
-    sessionId: null,
-    key: null,
-    exp: null,
-    connected: false,
-    deviceType: null,
-    hasCamera: false,
-  },
-};
-
-export const useSessionStore = createWithEqualityFn<SessionStore>()(
-  (set) => ({
-    ...sessionStoreInitialState,
-    changeRequest: (request: QRRequest) => set({ request }),
-    changeSession: (session: Session) => set({ session }),
-  }),
-  shallow
-);
diff --git a/packages/dapp/src/utils/prisma.ts b/packages/dapp/src/utils/prisma.ts
deleted file mode 100644
index e2b960527..000000000
--- a/packages/dapp/src/utils/prisma.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { PrismaClient } from '@prisma/client';
-
-const globalForPrisma = globalThis as unknown as {
-  prisma: PrismaClient | undefined;
-};
-
-export const prisma = globalForPrisma.prisma ?? new PrismaClient();
-
-if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
diff --git a/packages/dapp/src/utils/supabase/database.types.ts b/packages/dapp/src/utils/supabase/database.types.ts
index 11e46f2f8..f535b41da 100644
--- a/packages/dapp/src/utils/supabase/database.types.ts
+++ b/packages/dapp/src/utils/supabase/database.types.ts
@@ -173,6 +173,38 @@ export type Database = {
         }
         Relationships: []
       }
+      encrypted_sessions: {
+        Row: {
+          connected: boolean
+          data: string | null
+          id: string
+          iv: string | null
+          user_id: string
+        }
+        Insert: {
+          connected?: boolean
+          data?: string | null
+          id?: string
+          iv?: string | null
+          user_id: string
+        }
+        Update: {
+          connected?: boolean
+          data?: string | null
+          id?: string
+          iv?: string | null
+          user_id?: string
+        }
+        Relationships: [
+          {
+            foreignKeyName: "public_encrypted-sessions_user_id_fkey"
+            columns: ["user_id"]
+            isOneToOne: false
+            referencedRelation: "users"
+            referencedColumns: ["id"]
+          }
+        ]
+      }
       presentations: {
         Row: {
           created_at: string
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 9f8174350..c19394163 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,5 +1,9 @@
 lockfileVersion: '6.0'
 
+settings:
+  autoInstallPeers: true
+  excludeLinksFromLockfile: false
+
 patchedDependencies:
   '@ceramicnetwork/common@2.30.0':
     hash: uqwtqun5atcy5jjekxssfbohei
@@ -84,7 +88,7 @@ importers:
         version: 9.0.0(eslint@8.52.0)
       eslint-plugin-import:
         specifier: ^2.29.0
-        version: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
+        version: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0)
       eslint-plugin-jest:
         specifier: ^27.4.3
         version: 27.4.3(@typescript-eslint/eslint-plugin@6.9.0)(eslint@8.52.0)(typescript@5.2.2)
@@ -403,9 +407,6 @@ importers:
       '@nextui-org/react':
         specifier: ^2.2.9
         version: 2.2.9(@types/react@18.2.33)(framer-motion@10.16.5)(react-dom@18.2.0)(react@18.2.0)(tailwind-variants@0.1.19)(tailwindcss@3.3.5)
-      '@prisma/client':
-        specifier: ^5.7.0
-        version: 5.7.0(prisma@5.7.0)
       '@radix-ui/react-toast':
         specifier: ^1.1.5
         version: 1.1.5(@types/react-dom@18.2.14)(@types/react@18.2.33)(react-dom@18.2.0)(react@18.2.0)
@@ -514,9 +515,6 @@ importers:
       pino-pretty:
         specifier: ^10.3.1
         version: 10.3.1
-      prisma:
-        specifier: ^5.7.0
-        version: 5.7.0
       qrcode.react:
         specifier: ^3.1.0
         version: 3.1.0(react@18.2.0)
@@ -4096,12 +4094,12 @@ packages:
       semver: 7.5.4
       serve-handler: 6.1.5
       shelljs: 0.8.5
-      terser-webpack-plugin: 5.3.9(@swc/core@1.3.78)(esbuild@0.19.5)(webpack@5.89.0)
+      terser-webpack-plugin: 5.3.9(webpack@5.89.0)
       tslib: 2.6.2
       update-notifier: 5.1.0
       url-loader: 4.1.1(file-loader@6.2.0)(webpack@5.89.0)
       wait-on: 6.0.1
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
       webpack-bundle-analyzer: 4.9.1
       webpack-dev-server: 4.15.1(webpack@5.89.0)
       webpack-merge: 5.10.0
@@ -4220,7 +4218,7 @@ packages:
       tslib: 2.6.2
       unist-util-visit: 2.0.3
       utility-types: 3.10.0
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
     transitivePeerDependencies:
       - '@parcel/css'
       - '@swc/core'
@@ -4297,7 +4295,7 @@ packages:
       react: 18.2.0
       react-dom: 18.2.0(react@18.2.0)
       tslib: 2.6.2
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
     transitivePeerDependencies:
       - '@parcel/css'
       - '@swc/core'
@@ -4917,6 +4915,7 @@ packages:
     cpu: [arm64]
     os: [android]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/android-arm@0.18.20:
@@ -4934,6 +4933,7 @@ packages:
     cpu: [arm]
     os: [android]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/android-x64@0.18.20:
@@ -4951,6 +4951,7 @@ packages:
     cpu: [x64]
     os: [android]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/darwin-arm64@0.18.20:
@@ -4968,6 +4969,7 @@ packages:
     cpu: [arm64]
     os: [darwin]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/darwin-x64@0.18.20:
@@ -4985,6 +4987,7 @@ packages:
     cpu: [x64]
     os: [darwin]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/freebsd-arm64@0.18.20:
@@ -5002,6 +5005,7 @@ packages:
     cpu: [arm64]
     os: [freebsd]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/freebsd-x64@0.18.20:
@@ -5019,6 +5023,7 @@ packages:
     cpu: [x64]
     os: [freebsd]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/linux-arm64@0.18.20:
@@ -5036,6 +5041,7 @@ packages:
     cpu: [arm64]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/linux-arm@0.18.20:
@@ -5053,6 +5059,7 @@ packages:
     cpu: [arm]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/linux-ia32@0.18.20:
@@ -5070,6 +5077,7 @@ packages:
     cpu: [ia32]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/linux-loong64@0.18.20:
@@ -5087,6 +5095,7 @@ packages:
     cpu: [loong64]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/linux-mips64el@0.18.20:
@@ -5104,6 +5113,7 @@ packages:
     cpu: [mips64el]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/linux-ppc64@0.18.20:
@@ -5121,6 +5131,7 @@ packages:
     cpu: [ppc64]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/linux-riscv64@0.18.20:
@@ -5138,6 +5149,7 @@ packages:
     cpu: [riscv64]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/linux-s390x@0.18.20:
@@ -5155,6 +5167,7 @@ packages:
     cpu: [s390x]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/linux-x64@0.18.20:
@@ -5172,6 +5185,7 @@ packages:
     cpu: [x64]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/netbsd-x64@0.18.20:
@@ -5189,6 +5203,7 @@ packages:
     cpu: [x64]
     os: [netbsd]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/openbsd-x64@0.18.20:
@@ -5206,6 +5221,7 @@ packages:
     cpu: [x64]
     os: [openbsd]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/sunos-x64@0.18.20:
@@ -5223,6 +5239,7 @@ packages:
     cpu: [x64]
     os: [sunos]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/win32-arm64@0.18.20:
@@ -5240,6 +5257,7 @@ packages:
     cpu: [arm64]
     os: [win32]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/win32-ia32@0.18.20:
@@ -5257,6 +5275,7 @@ packages:
     cpu: [ia32]
     os: [win32]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@esbuild/win32-x64@0.18.20:
@@ -5274,6 +5293,7 @@ packages:
     cpu: [x64]
     os: [win32]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@eslint-community/eslint-utils@4.4.0(eslint@8.52.0):
@@ -9113,51 +9133,6 @@ packages:
   /@polka/url@1.0.0-next.23:
     resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==}
 
-  /@prisma/client@5.7.0(prisma@5.7.0):
-    resolution: {integrity: sha512-cZmglCrfNbYpzUtz7HscVHl38e9CrUs31nrVoGUK1nIPXGgt8hT4jj2s657UXcNdQ/jBUxDgGmHyu2Nyrq1txg==}
-    engines: {node: '>=16.13'}
-    requiresBuild: true
-    peerDependencies:
-      prisma: '*'
-    peerDependenciesMeta:
-      prisma:
-        optional: true
-    dependencies:
-      prisma: 5.7.0
-    dev: false
-
-  /@prisma/debug@5.7.0:
-    resolution: {integrity: sha512-tZ+MOjWlVvz1kOEhNYMa4QUGURY+kgOUBqLHYIV8jmCsMuvA1tWcn7qtIMLzYWCbDcQT4ZS8xDgK0R2gl6/0wA==}
-    dev: false
-
-  /@prisma/engines-version@5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9:
-    resolution: {integrity: sha512-V6tgRVi62jRwTm0Hglky3Scwjr/AKFBFtS+MdbsBr7UOuiu1TKLPc6xfPiyEN1+bYqjEtjxwGsHgahcJsd1rNg==}
-    dev: false
-
-  /@prisma/engines@5.7.0:
-    resolution: {integrity: sha512-TkOMgMm60n5YgEKPn9erIvFX2/QuWnl3GBo6yTRyZKk5O5KQertXiNnrYgSLy0SpsKmhovEPQb+D4l0SzyE7XA==}
-    requiresBuild: true
-    dependencies:
-      '@prisma/debug': 5.7.0
-      '@prisma/engines-version': 5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9
-      '@prisma/fetch-engine': 5.7.0
-      '@prisma/get-platform': 5.7.0
-    dev: false
-
-  /@prisma/fetch-engine@5.7.0:
-    resolution: {integrity: sha512-zIn/qmO+N/3FYe7/L9o+yZseIU8ivh4NdPKSkQRIHfg2QVTVMnbhGoTcecbxfVubeTp+DjcbjS0H9fCuM4W04w==}
-    dependencies:
-      '@prisma/debug': 5.7.0
-      '@prisma/engines-version': 5.7.0-41.79fb5193cf0a8fdbef536e4b4a159cad677ab1b9
-      '@prisma/get-platform': 5.7.0
-    dev: false
-
-  /@prisma/get-platform@5.7.0:
-    resolution: {integrity: sha512-ZeV/Op4bZsWXuw5Tg05WwRI8BlKiRFhsixPcAM+5BKYSiUZiMKIi713tfT3drBq8+T0E1arNZgYSA9QYcglWNA==}
-    dependencies:
-      '@prisma/debug': 5.7.0
-    dev: false
-
   /@radix-ui/primitive@1.0.1:
     resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
     dependencies:
@@ -11329,6 +11304,7 @@ packages:
     cpu: [arm64]
     os: [darwin]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@swc/core-darwin-x64@1.3.78:
@@ -11337,6 +11313,7 @@ packages:
     cpu: [x64]
     os: [darwin]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@swc/core-linux-arm-gnueabihf@1.3.78:
@@ -11345,6 +11322,7 @@ packages:
     cpu: [arm]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@swc/core-linux-arm64-gnu@1.3.78:
@@ -11353,6 +11331,7 @@ packages:
     cpu: [arm64]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@swc/core-linux-arm64-musl@1.3.78:
@@ -11361,6 +11340,7 @@ packages:
     cpu: [arm64]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@swc/core-linux-x64-gnu@1.3.78:
@@ -11369,6 +11349,7 @@ packages:
     cpu: [x64]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@swc/core-linux-x64-musl@1.3.78:
@@ -11377,6 +11358,7 @@ packages:
     cpu: [x64]
     os: [linux]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@swc/core-win32-arm64-msvc@1.3.78:
@@ -11385,6 +11367,7 @@ packages:
     cpu: [arm64]
     os: [win32]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@swc/core-win32-ia32-msvc@1.3.78:
@@ -11393,6 +11376,7 @@ packages:
     cpu: [ia32]
     os: [win32]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@swc/core-win32-x64-msvc@1.3.78:
@@ -11401,6 +11385,7 @@ packages:
     cpu: [x64]
     os: [win32]
     requiresBuild: true
+    dev: true
     optional: true
 
   /@swc/core@1.3.78:
@@ -11423,6 +11408,7 @@ packages:
       '@swc/core-win32-arm64-msvc': 1.3.78
       '@swc/core-win32-ia32-msvc': 1.3.78
       '@swc/core-win32-x64-msvc': 1.3.78
+    dev: true
 
   /@swc/helpers@0.4.14:
     resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==}
@@ -13477,6 +13463,7 @@ packages:
     dependencies:
       webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
       webpack-cli: 5.1.4(webpack@5.89.0)
+    dev: true
 
   /@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.89.0):
     resolution: {integrity: sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==}
@@ -13487,6 +13474,7 @@ packages:
     dependencies:
       webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
       webpack-cli: 5.1.4(webpack@5.89.0)
+    dev: true
 
   /@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack@5.89.0):
     resolution: {integrity: sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==}
@@ -13501,6 +13489,7 @@ packages:
     dependencies:
       webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
       webpack-cli: 5.1.4(webpack@5.89.0)
+    dev: true
 
   /@xmldom/xmldom@0.7.13:
     resolution: {integrity: sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==}
@@ -14216,7 +14205,7 @@ packages:
       loader-utils: 2.0.4
       make-dir: 3.1.0
       schema-utils: 2.7.1
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
 
   /babel-plugin-apply-mdx-type-prop@1.6.22(@babel/core@7.12.9):
     resolution: {integrity: sha512-VefL+8o+F/DfK24lPZMtJctrCVOfgbqLAGZSkxwhazQv4VxPg3Za/i40fu22KR2m8eEda+IfSOlPLUSIiLcnCQ==}
@@ -15881,7 +15870,7 @@ packages:
       normalize-path: 3.0.0
       schema-utils: 4.2.0
       serialize-javascript: 6.0.1
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
 
   /core-js-compat@3.32.0:
     resolution: {integrity: sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw==}
@@ -16184,7 +16173,7 @@ packages:
       postcss-modules-values: 4.0.0(postcss@8.4.31)
       postcss-value-parser: 4.2.0
       semver: 7.5.4
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
 
   /css-minimizer-webpack-plugin@4.2.2(clean-css@5.3.2)(webpack@5.89.0):
     resolution: {integrity: sha512-s3Of/4jKfw1Hj9CxEO1E5oXhQAxlayuHO2y/ML+C6I9sQ7FdzfEV6QgMLN3vI+qFsjJGIAFLKtQK7t8BOXAIyA==}
@@ -16218,7 +16207,7 @@ packages:
       schema-utils: 4.2.0
       serialize-javascript: 6.0.1
       source-map: 0.6.1
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
 
   /css-select@4.3.0:
     resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==}
@@ -17475,6 +17464,7 @@ packages:
       '@esbuild/win32-arm64': 0.19.5
       '@esbuild/win32-ia32': 0.19.5
       '@esbuild/win32-x64': 0.19.5
+    dev: true
 
   /escalade@3.1.1:
     resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
@@ -17521,7 +17511,7 @@ packages:
     dependencies:
       confusing-browser-globals: 1.0.11
       eslint: 8.52.0
-      eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
+      eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0)
       object.assign: 4.1.4
       object.entries: 1.1.6
       semver: 6.3.1
@@ -17539,7 +17529,7 @@ packages:
       '@typescript-eslint/parser': 6.9.0(eslint@8.52.0)(typescript@5.2.2)
       eslint: 8.52.0
       eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.29.0)(eslint@8.52.0)
-      eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
+      eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0)
     dev: true
 
   /eslint-config-next@13.5.6(eslint@8.55.0)(typescript@5.3.3):
@@ -17557,7 +17547,7 @@ packages:
       eslint: 8.55.0
       eslint-import-resolver-node: 0.3.9
       eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.0)(eslint@8.55.0)
-      eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
+      eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint@8.55.0)
       eslint-plugin-jsx-a11y: 6.7.1(eslint@8.55.0)
       eslint-plugin-react: 7.33.2(eslint@8.55.0)
       eslint-plugin-react-hooks: 4.6.0(eslint@8.55.0)
@@ -17597,7 +17587,7 @@ packages:
       enhanced-resolve: 5.15.0
       eslint: 8.55.0
       eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
-      eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
+      eslint-plugin-import: 2.29.0(@typescript-eslint/parser@6.9.0)(eslint@8.55.0)
       fast-glob: 3.3.1
       get-tsconfig: 4.7.2
       is-core-module: 2.13.1
@@ -17639,7 +17629,65 @@ packages:
       - supports-color
     dev: true
 
-  /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0):
+  /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-node@0.3.9)(eslint@8.52.0):
+    resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint: '*'
+      eslint-import-resolver-node: '*'
+      eslint-import-resolver-typescript: '*'
+      eslint-import-resolver-webpack: '*'
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+      eslint:
+        optional: true
+      eslint-import-resolver-node:
+        optional: true
+      eslint-import-resolver-typescript:
+        optional: true
+      eslint-import-resolver-webpack:
+        optional: true
+    dependencies:
+      '@typescript-eslint/parser': 6.9.0(eslint@8.52.0)(typescript@5.2.2)
+      debug: 3.2.7
+      eslint: 8.52.0
+      eslint-import-resolver-node: 0.3.9
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /eslint-module-utils@2.8.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-node@0.3.9)(eslint@8.55.0):
+    resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint: '*'
+      eslint-import-resolver-node: '*'
+      eslint-import-resolver-typescript: '*'
+      eslint-import-resolver-webpack: '*'
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+      eslint:
+        optional: true
+      eslint-import-resolver-node:
+        optional: true
+      eslint-import-resolver-typescript:
+        optional: true
+      eslint-import-resolver-webpack:
+        optional: true
+    dependencies:
+      '@typescript-eslint/parser': 6.9.0(eslint@8.52.0)(typescript@5.2.2)
+      debug: 3.2.7
+      eslint: 8.55.0
+      eslint-import-resolver-node: 0.3.9
+    transitivePeerDependencies:
+      - supports-color
+    dev: true
+
+  /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.9.0)(eslint@8.52.0):
     resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==}
     engines: {node: '>=4'}
     peerDependencies:
@@ -17649,7 +17697,42 @@ packages:
       '@typescript-eslint/parser':
         optional: true
     dependencies:
-      '@typescript-eslint/parser': 6.9.0(eslint@8.55.0)(typescript@5.3.3)
+      '@typescript-eslint/parser': 6.9.0(eslint@8.52.0)(typescript@5.2.2)
+      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
+      doctrine: 2.1.0
+      eslint: 8.52.0
+      eslint-import-resolver-node: 0.3.9
+      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-node@0.3.9)(eslint@8.52.0)
+      hasown: 2.0.0
+      is-core-module: 2.13.1
+      is-glob: 4.0.3
+      minimatch: 3.1.2
+      object.fromentries: 2.0.7
+      object.groupby: 1.0.1
+      object.values: 1.1.7
+      semver: 6.3.1
+      tsconfig-paths: 3.14.2
+    transitivePeerDependencies:
+      - eslint-import-resolver-typescript
+      - eslint-import-resolver-webpack
+      - supports-color
+    dev: true
+
+  /eslint-plugin-import@2.29.0(@typescript-eslint/parser@6.9.0)(eslint@8.55.0):
+    resolution: {integrity: sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==}
+    engines: {node: '>=4'}
+    peerDependencies:
+      '@typescript-eslint/parser': '*'
+      eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8
+    peerDependenciesMeta:
+      '@typescript-eslint/parser':
+        optional: true
+    dependencies:
+      '@typescript-eslint/parser': 6.9.0(eslint@8.52.0)(typescript@5.2.2)
       array-includes: 3.1.7
       array.prototype.findlastindex: 1.2.3
       array.prototype.flat: 1.3.2
@@ -17658,7 +17741,7 @@ packages:
       doctrine: 2.1.0
       eslint: 8.55.0
       eslint-import-resolver-node: 0.3.9
-      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1)(eslint@8.55.0)
+      eslint-module-utils: 2.8.0(@typescript-eslint/parser@6.9.0)(eslint-import-resolver-node@0.3.9)(eslint@8.55.0)
       hasown: 2.0.0
       is-core-module: 2.13.1
       is-glob: 4.0.3
@@ -18543,6 +18626,7 @@ packages:
   /fastest-levenshtein@1.0.16:
     resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==}
     engines: {node: '>= 4.9.1'}
+    dev: true
 
   /fastfile@0.0.20:
     resolution: {integrity: sha512-r5ZDbgImvVWCP0lA/cGNgQcZqR+aYdFx3u+CtJqUE510pBUVGMn4ulL/iRTI4tACTYsNJ736uzFxEBXesPAktA==}
@@ -18672,7 +18756,7 @@ packages:
     dependencies:
       loader-utils: 2.0.4
       schema-utils: 3.3.0
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
 
   /file-saver@2.0.5:
     resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
@@ -18911,7 +18995,7 @@ packages:
       semver: 7.5.4
       tapable: 1.1.3
       typescript: 5.3.3
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
 
   /form-data@3.0.1:
     resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==}
@@ -19810,7 +19894,7 @@ packages:
       lodash: 4.17.21
       pretty-error: 4.0.0
       tapable: 2.2.1
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
 
   /html5-qrcode@2.3.8:
     resolution: {integrity: sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ==}
@@ -20050,6 +20134,7 @@ packages:
     dependencies:
       pkg-dir: 4.2.0
       resolve-cwd: 3.0.0
+    dev: true
 
   /imurmurhash@0.1.4:
     resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==}
@@ -20174,6 +20259,7 @@ packages:
   /interpret@3.1.1:
     resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==}
     engines: {node: '>=10.13.0'}
+    dev: true
 
   /intl-messageformat@10.5.8:
     resolution: {integrity: sha512-NRf0jpBWV0vd671G5b06wNofAN8tp7WWDogMZyaU8GUAsmbouyvgwmFJI7zLjfAMpm3zK+vSwRP3jzaoIcMbaA==}
@@ -22941,7 +23027,7 @@ packages:
       webpack: ^5.0.0
     dependencies:
       schema-utils: 4.2.0
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
 
   /minimalistic-assert@1.0.1:
     resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==}
@@ -24506,7 +24592,7 @@ packages:
       jiti: 1.20.0
       postcss: 8.4.31
       semver: 7.5.4
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
     transitivePeerDependencies:
       - typescript
 
@@ -25024,15 +25110,6 @@ packages:
       react: 18.2.0
     dev: false
 
-  /prisma@5.7.0:
-    resolution: {integrity: sha512-0rcfXO2ErmGAtxnuTNHQT9ztL0zZheQjOI/VNJzdq87C3TlGPQtMqtM+KCwU6XtmkoEr7vbCQqA7HF9IY0ST+Q==}
-    engines: {node: '>=16.13'}
-    hasBin: true
-    requiresBuild: true
-    dependencies:
-      '@prisma/engines': 5.7.0
-    dev: false
-
   /prismjs@1.29.0:
     resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==}
     engines: {node: '>=6'}
@@ -25390,7 +25467,7 @@ packages:
       strip-ansi: 6.0.1
       text-table: 0.2.0
       typescript: 5.3.3
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
     transitivePeerDependencies:
       - eslint
       - supports-color
@@ -25494,7 +25571,7 @@ packages:
     dependencies:
       '@babel/runtime': 7.23.2
       react-loadable: /@docusaurus/react-loadable@5.5.2(react@18.2.0)
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
 
   /react-native-securerandom@0.1.1(react-native@0.72.6):
     resolution: {integrity: sha512-CozcCx0lpBLevxiXEb86kwLRalBCHNjiGPlw3P7Fi27U6ZLdfjOCNRHD1LtBKcvPvI3TvkBXB3GOtLvqaYJLGw==}
@@ -25901,6 +25978,7 @@ packages:
     engines: {node: '>= 10.13.0'}
     dependencies:
       resolve: 1.22.4
+    dev: true
 
   /recursive-readdir@2.2.3:
     resolution: {integrity: sha512-8HrF5ZsXk5FAH9dgsx3BlUer73nIhuj+9OrQwEbLTPOBzGkL1lsFCR01am+v+0m2Cmbs1nP12hLDl5FA7EszKA==}
@@ -26121,6 +26199,7 @@ packages:
     engines: {node: '>=8'}
     dependencies:
       resolve-from: 5.0.0
+    dev: true
 
   /resolve-from@3.0.0:
     resolution: {integrity: sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==}
@@ -27650,7 +27729,7 @@ packages:
       normalize-path: 3.0.0
       schema-utils: 4.2.0
       stylelint: 15.11.0(typescript@5.3.3)
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
     dev: true
 
   /stylelint@15.11.0(typescript@5.3.3):
@@ -28067,6 +28146,78 @@ packages:
       serialize-javascript: 6.0.1
       terser: 5.22.0
       webpack: 5.89.0(@swc/core@1.3.78)(esbuild@0.19.5)
+    dev: true
+
+  /terser-webpack-plugin@5.3.9(esbuild@0.18.20)(webpack@5.89.0):
+    resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
+    engines: {node: '>= 10.13.0'}
+    peerDependencies:
+      '@swc/core': '*'
+      esbuild: '*'
+      uglify-js: '*'
+      webpack: ^5.1.0
+    peerDependenciesMeta:
+      '@swc/core':
+        optional: true
+      esbuild:
+        optional: true
+      uglify-js:
+        optional: true
+    dependencies:
+      '@jridgewell/trace-mapping': 0.3.20
+      esbuild: 0.18.20
+      jest-worker: 27.5.1
+      schema-utils: 3.3.0
+      serialize-javascript: 6.0.1
+      terser: 5.22.0
+      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+    dev: true
+
+  /terser-webpack-plugin@5.3.9(webpack@5.88.2):
+    resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
+    engines: {node: '>= 10.13.0'}
+    peerDependencies:
+      '@swc/core': '*'
+      esbuild: '*'
+      uglify-js: '*'
+      webpack: ^5.1.0
+    peerDependenciesMeta:
+      '@swc/core':
+        optional: true
+      esbuild:
+        optional: true
+      uglify-js:
+        optional: true
+    dependencies:
+      '@jridgewell/trace-mapping': 0.3.20
+      jest-worker: 27.5.1
+      schema-utils: 3.3.0
+      serialize-javascript: 6.0.1
+      terser: 5.22.0
+      webpack: 5.88.2
+
+  /terser-webpack-plugin@5.3.9(webpack@5.89.0):
+    resolution: {integrity: sha512-ZuXsqE07EcggTWQjXUj+Aot/OMcD0bMKGgF63f7UxYcu5/AJF53aIpK1YoP5xR9l6s/Hy2b+t1AM0bLNPRuhwA==}
+    engines: {node: '>= 10.13.0'}
+    peerDependencies:
+      '@swc/core': '*'
+      esbuild: '*'
+      uglify-js: '*'
+      webpack: ^5.1.0
+    peerDependenciesMeta:
+      '@swc/core':
+        optional: true
+      esbuild:
+        optional: true
+      uglify-js:
+        optional: true
+    dependencies:
+      '@jridgewell/trace-mapping': 0.3.20
+      jest-worker: 27.5.1
+      schema-utils: 3.3.0
+      serialize-javascript: 6.0.1
+      terser: 5.22.0
+      webpack: 5.89.0
 
   /terser@5.22.0:
     resolution: {integrity: sha512-hHZVLgRA2z4NWcN6aS5rQDc+7Dcy58HOf2zbYwmFcQ+ua3h6eEFf5lIDKTzbWwlazPyOZsFQO8V80/IjVNExEw==}
@@ -29049,7 +29200,7 @@ packages:
       loader-utils: 2.0.4
       mime-types: 2.1.35
       schema-utils: 3.3.0
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
 
   /url-parse-lax@3.0.0:
     resolution: {integrity: sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==}
@@ -29756,6 +29907,7 @@ packages:
       rechoir: 0.8.0
       webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
       webpack-merge: 5.9.0
+    dev: true
 
   /webpack-dev-middleware@5.3.3(webpack@5.89.0):
     resolution: {integrity: sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==}
@@ -29768,7 +29920,7 @@ packages:
       mime-types: 2.1.35
       range-parser: 1.2.1
       schema-utils: 4.2.0
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
 
   /webpack-dev-server@4.15.1(webpack@5.89.0):
     resolution: {integrity: sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==}
@@ -29811,7 +29963,7 @@ packages:
       serve-index: 1.9.1
       sockjs: 0.3.24
       spdy: 4.0.2
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
       webpack-dev-middleware: 5.3.3(webpack@5.89.0)
       ws: 8.14.2
     transitivePeerDependencies:
@@ -29877,7 +30029,46 @@ packages:
       neo-async: 2.6.2
       schema-utils: 3.3.0
       tapable: 2.2.1
-      terser-webpack-plugin: 5.3.9(@swc/core@1.3.78)(esbuild@0.19.5)(webpack@5.89.0)
+      terser-webpack-plugin: 5.3.9(webpack@5.88.2)
+      watchpack: 2.4.0
+      webpack-sources: 3.2.3
+    transitivePeerDependencies:
+      - '@swc/core'
+      - esbuild
+      - uglify-js
+
+  /webpack@5.89.0:
+    resolution: {integrity: sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==}
+    engines: {node: '>=10.13.0'}
+    hasBin: true
+    peerDependencies:
+      webpack-cli: '*'
+    peerDependenciesMeta:
+      webpack-cli:
+        optional: true
+    dependencies:
+      '@types/eslint-scope': 3.7.6
+      '@types/estree': 1.0.3
+      '@webassemblyjs/ast': 1.11.6
+      '@webassemblyjs/wasm-edit': 1.11.6
+      '@webassemblyjs/wasm-parser': 1.11.6
+      acorn: 8.10.0
+      acorn-import-assertions: 1.9.0(acorn@8.10.0)
+      browserslist: 4.22.1
+      chrome-trace-event: 1.0.3
+      enhanced-resolve: 5.15.0
+      es-module-lexer: 1.3.1
+      eslint-scope: 5.1.1
+      events: 3.3.0
+      glob-to-regexp: 0.4.1
+      graceful-fs: 4.2.11
+      json-parse-even-better-errors: 2.3.1
+      loader-runner: 4.3.0
+      mime-types: 2.1.35
+      neo-async: 2.6.2
+      schema-utils: 3.3.0
+      tapable: 2.2.1
+      terser-webpack-plugin: 5.3.9(webpack@5.89.0)
       watchpack: 2.4.0
       webpack-sources: 3.2.3
     transitivePeerDependencies:
@@ -29923,6 +30114,7 @@ packages:
       - '@swc/core'
       - esbuild
       - uglify-js
+    dev: true
 
   /webpack@5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4):
     resolution: {integrity: sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==}
@@ -29955,7 +30147,7 @@ packages:
       neo-async: 2.6.2
       schema-utils: 3.3.0
       tapable: 2.2.1
-      terser-webpack-plugin: 5.3.9(@swc/core@1.3.78)(esbuild@0.19.5)(webpack@5.89.0)
+      terser-webpack-plugin: 5.3.9(esbuild@0.18.20)(webpack@5.89.0)
       watchpack: 2.4.0
       webpack-cli: 5.1.4(webpack@5.89.0)
       webpack-sources: 3.2.3
@@ -29963,6 +30155,7 @@ packages:
       - '@swc/core'
       - esbuild
       - uglify-js
+    dev: true
 
   /webpackbar@5.0.2(webpack@5.89.0):
     resolution: {integrity: sha512-BmFJo7veBDgQzfWXl/wwYXr/VFus0614qZ8i9znqcl9fnEdiVkdbi0TedLQ6xAK92HZHDJ0QmyQ0fmuZPAgCYQ==}
@@ -29974,7 +30167,7 @@ packages:
       consola: 2.15.3
       pretty-time: 1.1.0
       std-env: 3.4.3
-      webpack: 5.89.0(esbuild@0.18.20)(webpack-cli@5.1.4)
+      webpack: 5.89.0
 
   /websocket-driver@0.7.4:
     resolution: {integrity: sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==}
@@ -30514,7 +30707,3 @@ packages:
       - expo
       - react-native
       - web-streams-polyfill
-
-settings:
-  autoInstallPeers: true
-  excludeLinksFromLockfile: false