From 6c067a3b6aef3eb6f2f5e07de638dab6a6512b26 Mon Sep 17 00:00:00 2001 From: akd Date: Sun, 29 Dec 2024 11:04:09 +0100 Subject: [PATCH] feat: make Clerk auth in insights app --- .../src/app/api/insights/route.ts | 28 ++- .../components/all-insights/all-insights.tsx | 6 +- apps/insights-app/src/app/layout.tsx | 18 +- apps/insights-app/src/app/page.tsx | 40 +--- apps/insights-app/src/config.ts | 1 - apps/insights-app/src/middleware.ts | 12 + docker-compose.yml | 4 +- .../components/user-session/user-session.tsx | 4 +- libs/common-ui/src/main.ts | 4 +- package-lock.json | 206 +++++++++++++++++- package.json | 1 + 11 files changed, 263 insertions(+), 61 deletions(-) create mode 100644 apps/insights-app/src/middleware.ts diff --git a/apps/insights-app/src/app/api/insights/route.ts b/apps/insights-app/src/app/api/insights/route.ts index ffb22f1..2a0e00b 100644 --- a/apps/insights-app/src/app/api/insights/route.ts +++ b/apps/insights-app/src/app/api/insights/route.ts @@ -1,13 +1,25 @@ -import { utilFetch } from '@lifeis/common-ui'; +import { getAuth } from '@clerk/nextjs/server'; +import { Client } from '@notionhq/client'; +import { NextRequest, NextResponse } from 'next/server'; +import { PageObjectResponse } from '@notionhq/client/build/src/api-endpoints'; -export const GET = async (): Promise => { - const response = await utilFetch(`/insights`, { - method: 'GET', - }); +const notion = new Client({ auth: process.env.NEXT_NOTION_API_KEY }); +const insightsDatabaseId = 'caae7cadc59c43fe920dd5ce4048dade'; + +export const GET = async (req: NextRequest, res: NextResponse) => { + const { userId } = getAuth(req); - if (!response.ok) { - throw new Error('Failed to get logs'); + if (!userId) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); } - return response; + const response = await notion.databases.query({ + database_id: insightsDatabaseId, + }); + // objects; + const insights = response.results.map((obj) => + ((obj as PageObjectResponse).properties.insight as any).title.map((title: any) => title.plain_text).join(', '), + ); + + return NextResponse.json(insights, { status: 200 }); }; diff --git a/apps/insights-app/src/app/components/all-insights/all-insights.tsx b/apps/insights-app/src/app/components/all-insights/all-insights.tsx index 35d5cbe..a9a7e09 100644 --- a/apps/insights-app/src/app/components/all-insights/all-insights.tsx +++ b/apps/insights-app/src/app/components/all-insights/all-insights.tsx @@ -1,12 +1,14 @@ +'use client'; + import React, { useEffect, useState } from 'react'; -import { GET } from '../../api/insights/route'; +// import { GET } from '../../api/insights/route'; export const AllInsights = () => { const [insights, setInsights] = useState([]); useEffect(() => { const fetchLogs = async () => { - const insightsResponse = await GET(); + const insightsResponse = await fetch('/api/insights'); const insights = await insightsResponse.json(); setInsights(insights); }; diff --git a/apps/insights-app/src/app/layout.tsx b/apps/insights-app/src/app/layout.tsx index c85be1f..12b4630 100644 --- a/apps/insights-app/src/app/layout.tsx +++ b/apps/insights-app/src/app/layout.tsx @@ -5,10 +5,22 @@ export const metadata = { description: 'Generated by create-nx-workspace', }; +import { ClerkProvider, SignInButton, SignedIn, SignedOut, UserButton } from '@clerk/nextjs'; + export default function RootLayout({ children }: { children: React.ReactNode }) { return ( - - {children} - + + + + + + + + + + {children} + + + ); } diff --git a/apps/insights-app/src/app/page.tsx b/apps/insights-app/src/app/page.tsx index 3c3f408..dfc2fba 100644 --- a/apps/insights-app/src/app/page.tsx +++ b/apps/insights-app/src/app/page.tsx @@ -1,39 +1,13 @@ -'use client'; - -import { init, isUserLoggedIn, UserSession } from '@lifeis/common-ui'; -import { useEffect, useState } from 'react'; - -import { CONFIG } from '../config'; -import { GoogleOAuthProvider } from '@react-oauth/google'; import { AllInsights } from './components/all-insights/all-insights'; +import { auth, currentUser } from '@clerk/nextjs/server'; -export default function Index() { - const [isLoggedIn, setIsLoggedIn] = useState(isUserLoggedIn()); - const [isInitialized, setIsInitialized] = useState(false); - - useEffect(() => { - init({ - beUrl: CONFIG.BE_URL, - clientId: CONFIG.CLIENT_ID, - app: 'insights', - }); - setIsInitialized(true); - }, []); +export default async function Index() { + // const { userId } = await auth(); return ( - -
- setIsLoggedIn(true)} - onLogOut={() => setIsLoggedIn(false)} - /> -
- {isLoggedIn && isInitialized && ( -
- -
- )} -
+
+ + {/* {userId} */} +
); } diff --git a/apps/insights-app/src/config.ts b/apps/insights-app/src/config.ts index 45b6cec..f8631fd 100644 --- a/apps/insights-app/src/config.ts +++ b/apps/insights-app/src/config.ts @@ -1,4 +1,3 @@ export const CONFIG = { BE_URL: `${process.env.NEXT_PUBLIC_BE || 'http://localhost:3000'}/api`, - CLIENT_ID: process.env.NEXT_PUBLIC_CLIENT_ID as string, }; diff --git a/apps/insights-app/src/middleware.ts b/apps/insights-app/src/middleware.ts new file mode 100644 index 0000000..d284023 --- /dev/null +++ b/apps/insights-app/src/middleware.ts @@ -0,0 +1,12 @@ +import { clerkMiddleware } from '@clerk/nextjs/server'; + +export default clerkMiddleware(); + +export const config = { + matcher: [ + // Skip Next.js internals and all static files, unless found in search params + '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)', + // Always run for API routes + '/(api|trpc)(.*)', + ], +}; diff --git a/docker-compose.yml b/docker-compose.yml index 1385b4f..1655747 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -59,7 +59,9 @@ services: - ${INSIGHTS_PORT}:4200 environment: - NEXT_PUBLIC_BE=${NGINX_DOMAIN} - - NEXT_PUBLIC_CLIENT_ID=${INSIGHTS_CLIENT_ID} + - NEXT_NOTION_API_KEY=${NOTION_API_KEY} + - NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=${NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY} + - CLERK_SECRET_KEY=${CLERK_SECRET_KEY} volumes: mono-node-modules: null diff --git a/libs/common-ui/src/lib/components/user-session/user-session.tsx b/libs/common-ui/src/lib/components/user-session/user-session.tsx index ff18453..94f4edc 100644 --- a/libs/common-ui/src/lib/components/user-session/user-session.tsx +++ b/libs/common-ui/src/lib/components/user-session/user-session.tsx @@ -26,11 +26,9 @@ export const UserSession = ({ isLoggedIn, isOfflineMode, onLoginSuccess, onLogOu {isLoggedIn ? (

- Welcome,{' '} alert('Срочно! Только что было определено, что Серега Я - космический бульбозавт')}> - User + Velkommen! - !

{!isOfflineMode && (
diff --git a/libs/common-ui/src/main.ts b/libs/common-ui/src/main.ts index 94fb1e8..c0c3328 100644 --- a/libs/common-ui/src/main.ts +++ b/libs/common-ui/src/main.ts @@ -1,6 +1,6 @@ interface IInitArgs { beUrl: string; - clientId: string; + clientId?: string; app?: string; isOffline?: boolean; } @@ -12,7 +12,7 @@ export const CONFIG = { isOffline: false, }; -export const init = ({ beUrl, clientId, app = '', isOffline = false }: IInitArgs) => { +export const init = ({ beUrl, clientId = '', app = '', isOffline = false }: IInitArgs) => { CONFIG.BE_URL = beUrl; CONFIG.CLIENT_ID = clientId; CONFIG.APP = app; diff --git a/package-lock.json b/package-lock.json index a8e834f..4de25f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "MIT", "dependencies": { + "@clerk/nextjs": "^6.9.6", "@deepgram/sdk": "3.9.0", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", @@ -2237,6 +2238,128 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@clerk/backend": { + "version": "1.21.4", + "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-1.21.4.tgz", + "integrity": "sha512-PHJzBJrTxBAvHwscXwUwpippT7nHhphgycVcFb3655Dq6q0nRdKfo5GlkDHscEKxLOdmppB/168nXsVwSWf86w==", + "dependencies": { + "@clerk/shared": "^2.20.4", + "@clerk/types": "^4.40.0", + "cookie": "0.7.0", + "snakecase-keys": "5.4.4", + "tslib": "2.4.1" + }, + "engines": { + "node": ">=18.17.0" + } + }, + "node_modules/@clerk/backend/node_modules/cookie": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.0.tgz", + "integrity": "sha512-qCf+V4dtlNhSRXGAZatc1TasyFO6GjohcOul807YOb5ik3+kQSnb4d7iajeCL8QHaJ4uZEjCgiCJerKXwdRVlQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@clerk/backend/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "node_modules/@clerk/clerk-react": { + "version": "5.21.0", + "resolved": "https://registry.npmjs.org/@clerk/clerk-react/-/clerk-react-5.21.0.tgz", + "integrity": "sha512-WGIYKeXA/cpvWj2NiMsWYJfRq4Npy6bM9ZrcTENXVox9jpk6iGggoX9zFJG9NBx5LDHBV2kgvpRdhnF/cnrJ+w==", + "dependencies": { + "@clerk/shared": "^2.20.4", + "@clerk/types": "^4.40.0", + "tslib": "2.4.1" + }, + "engines": { + "node": ">=18.17.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" + } + }, + "node_modules/@clerk/clerk-react/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "node_modules/@clerk/nextjs": { + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-6.9.6.tgz", + "integrity": "sha512-wmbQd2UYOnvGtidgEAqD6f2JZjvKMlmZqnT2HbR3GKwiGme3c1wLrkPye5tknaFLJHsA+Zfp7MJtL7mu07yCzw==", + "dependencies": { + "@clerk/backend": "^1.21.4", + "@clerk/clerk-react": "^5.21.0", + "@clerk/shared": "^2.20.4", + "@clerk/types": "^4.40.0", + "crypto-js": "4.2.0", + "server-only": "0.0.1", + "tslib": "2.4.1" + }, + "engines": { + "node": ">=18.17.0" + }, + "peerDependencies": { + "next": "^13.5.4 || ^14.0.3 || ^15.0.0", + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" + } + }, + "node_modules/@clerk/nextjs/node_modules/tslib": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==" + }, + "node_modules/@clerk/shared": { + "version": "2.20.4", + "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-2.20.4.tgz", + "integrity": "sha512-1ndGEO+NejIMFkl47DCeSpVv3nmKh9BHD6wt2Sl3X1wv7sj3eWzSVC14Exkag7D8Og2VcN4LXOFLErsCXHS+YQ==", + "hasInstallScript": true, + "dependencies": { + "@clerk/types": "^4.40.0", + "dequal": "2.0.3", + "glob-to-regexp": "0.4.1", + "js-cookie": "3.0.5", + "std-env": "^3.7.0", + "swr": "^2.2.0" + }, + "engines": { + "node": ">=18.17.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ^19.0.0 || ^19.0.0-0", + "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@clerk/types": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@clerk/types/-/types-4.40.0.tgz", + "integrity": "sha512-9QdllXYujsjYLbvPg9Kq1rWOemX5FB0r6Ijy8HOxwjKN+TPlxUnGcs+t7IwU+M5gdmZ2KV6aA6d1a2q2FlSoiA==", + "dependencies": { + "csstype": "3.1.1" + }, + "engines": { + "node": ">=18.17.0" + } + }, + "node_modules/@clerk/types/node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", @@ -12952,6 +13075,11 @@ "node": ">= 8" } }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, "node_modules/crypto-random-string": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", @@ -14044,7 +14172,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -16840,8 +16967,7 @@ "node_modules/glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" }, "node_modules/global-dirs": { "version": "3.0.1", @@ -19841,6 +19967,14 @@ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", "dev": true }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "engines": { + "node": ">=14" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -20690,7 +20824,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, "dependencies": { "tslib": "^2.0.3" } @@ -20805,6 +20938,17 @@ "tmpl": "1.0.5" } }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/markdown-table": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", @@ -22201,7 +22345,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" @@ -25529,6 +25672,11 @@ "node": ">= 0.8" } }, + "node_modules/server-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", + "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==" + }, "node_modules/set-function-length": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", @@ -25746,12 +25894,35 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", - "dev": true, "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, + "node_modules/snakecase-keys": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/snakecase-keys/-/snakecase-keys-5.4.4.tgz", + "integrity": "sha512-YTywJG93yxwHLgrYLZjlC75moVEX04LZM4FHfihjHe1FCXm+QaLOFfSf535aXOAd0ArVQMWUAe8ZPm4VtWyXaA==", + "dependencies": { + "map-obj": "^4.1.0", + "snake-case": "^3.0.4", + "type-fest": "^2.5.2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/snakecase-keys/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/socket.io-client": { "version": "4.7.5", "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", @@ -26019,8 +26190,7 @@ "node_modules/std-env": { "version": "3.7.0", "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.7.0.tgz", - "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==", - "dev": true + "integrity": "sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==" }, "node_modules/stream-events": { "version": "1.0.5", @@ -26654,6 +26824,18 @@ "url": "https://opencollective.com/svgo" } }, + "node_modules/swr": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/swr/-/swr-2.3.0.tgz", + "integrity": "sha512-NyZ76wA4yElZWBHzSgEJc28a0u6QZvhb6w0azeL2k7+Q1gAzVK+IqQYXhVOC/mzi+HZIozrZvBVeSeOZNR2bqA==", + "dependencies": { + "dequal": "^2.0.3", + "use-sync-external-store": "^1.4.0" + }, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -28073,6 +28255,14 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-sync-external-store": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.4.0.tgz", + "integrity": "sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index a2bfc7b..7366bbe 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "node": ">=v20.5.1" }, "dependencies": { + "@clerk/nextjs": "^6.9.6", "@deepgram/sdk": "3.9.0", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5",