diff --git a/apps/database-new/.env.local.example b/apps/database-new/.env.local.example new file mode 100644 index 00000000000..693703197a7 --- /dev/null +++ b/apps/database-new/.env.local.example @@ -0,0 +1,4 @@ +# Update these with your Supabase details from your project settings > API +# https://app.supabase.com/project/_/settings/api +NEXT_PUBLIC_SUPABASE_URL=your-project-url +NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key diff --git a/apps/database-new/.gitignore b/apps/database-new/.gitignore new file mode 100644 index 00000000000..fd3dbb571a1 --- /dev/null +++ b/apps/database-new/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/apps/database-new/README.md b/apps/database-new/README.md new file mode 100644 index 00000000000..9974f0c7625 --- /dev/null +++ b/apps/database-new/README.md @@ -0,0 +1,93 @@ + + Next.js and Supabase Starter Kit - the fastest way to build apps with Next.js and Supabase +

Next.js and Supabase Starter Kit

+
+ +

+ The fastest way to build apps with Next.js and Supabase +

+ +

+ Features · + Demo · + Deploy to Vercel · + Clone and run locally · + Feedback and issues + More Examples +

+
+ +## Features + +- Works across the entire [Next.js](https://nextjs.org) stack + - App Router + - Pages Router + - Middleware + - Client + - Server + - It just works! +- supabase-ssr. A package to configure Supabase Auth to use cookies +- Styling with [Tailwind CSS](https://tailwindcss.com) +- Optional deployment with [Supabase Vercel Integration and Vercel deploy](#deploy-your-own) + - Environment variables automatically assigned to Vercel project + +## Demo + +You can view a fully working demo at [demo-nextjs-with-supabase.vercel.app](https://demo-nextjs-with-supabase.vercel.app/). + +## Deploy to Vercel + +Vercel deployment will guide you through creating a Supabase account and project. + +After installation of the Supabase integration, all relevant environment variables will be assigned to the project so the deployment is fully functioning. + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-supabase&project-name=nextjs-with-supabase&repository-name=nextjs-with-supabase&demo-title=nextjs-with-supabase&demo-description=This%20starter%20configures%20Supabase%20Auth%20to%20use%20cookies%2C%20making%20the%20user's%20session%20available%20throughout%20the%20entire%20Next.js%20app%20-%20Client%20Components%2C%20Server%20Components%2C%20Route%20Handlers%2C%20Server%20Actions%20and%20Middleware.&demo-url=https%3A%2F%2Fdemo-nextjs-with-supabase.vercel.app%2F&external-id=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-supabase&demo-image=https%3A%2F%2Fdemo-nextjs-with-supabase.vercel.app%2Fopengraph-image.png&integration-ids=oac_VqOgBHqhEoFTPzGkPd7L0iH6) + +The above will also clone the Starter kit to your GitHub, you can clone that locally and develop locally. + +If you wish to just develop locally and not deploy to Vercel, [follow the steps below](#clone-and-run-locally). + +## Clone and run locally + +1. You'll first need a Supabase project which can be made [via the Supabase dashboard](https://database.new) + +2. Create a Next.js app using the Supabase Starter template npx command + + ```bash + npx create-next-app -e with-supabase + ``` + +3. Use `cd` to change into the app's directory + + ```bash + cd name-of-new-app + ``` + +4. Rename `.env.local.example` to `.env.local` and update the following: + + ``` + NEXT_PUBLIC_SUPABASE_URL=[INSERT SUPABASE PROJECT URL] + NEXT_PUBLIC_SUPABASE_ANON_KEY=[INSERT SUPABASE PROJECT API ANON KEY] + ``` + + Both `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY` can be found in [your Supabase project's API settings](https://app.supabase.com/project/_/settings/api) + +5. You can now run the Next.js local development server: + + ```bash + npm run dev + ``` + + The starter kit should now be running on [localhost:3000](http://localhost:3000/). + +> Check out [the docs for Local Development](https://supabase.com/docs/guides/getting-started/local-development) to also run Supabase locally. + +## Feedback and issues + +Please file feedback and issues over on the [Supabase GitHub org](https://github.com/supabase/supabase/issues/new/choose). + +## More Supabase examples + +- [Next.js Subscription Payments Starter](https://github.com/vercel/nextjs-subscription-payments) +- [Cookie-based Auth and the Next.js 13 App Router (free course)](https://youtube.com/playlist?list=PL5S4mPUpp4OtMhpnp93EFSo42iQ40XjbF) +- [Supabase Auth and the Next.js App Router](https://github.com/supabase/supabase/tree/master/examples/auth/nextjs) diff --git a/apps/database-new/app/auth/callback/route.ts b/apps/database-new/app/auth/callback/route.ts new file mode 100644 index 00000000000..3822631953d --- /dev/null +++ b/apps/database-new/app/auth/callback/route.ts @@ -0,0 +1,20 @@ +import { createClient } from '@/utils/supabase/server' +import { NextResponse } from 'next/server' +import { cookies } from 'next/headers' + +export async function GET(request: Request) { + // The `/auth/callback` route is required for the server-side auth flow implemented + // by the Auth Helpers package. It exchanges an auth code for the user's session. + // https://supabase.com/docs/guides/auth/auth-helpers/nextjs#managing-sign-in-with-code-exchange + const requestUrl = new URL(request.url) + const code = requestUrl.searchParams.get('code') + + if (code) { + const cookieStore = cookies() + const supabase = createClient(cookieStore) + await supabase.auth.exchangeCodeForSession(code) + } + + // URL to redirect to after sign in process completes + return NextResponse.redirect(requestUrl.origin) +} diff --git a/apps/database-new/app/favicon.ico b/apps/database-new/app/favicon.ico new file mode 100644 index 00000000000..718d6fea483 Binary files /dev/null and b/apps/database-new/app/favicon.ico differ diff --git a/apps/database-new/app/globals.css b/apps/database-new/app/globals.css new file mode 100644 index 00000000000..50bd9fc3356 --- /dev/null +++ b/apps/database-new/app/globals.css @@ -0,0 +1,42 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 200 20% 98%; + --btn-background: 200 10% 91%; + --btn-background-hover: 200 10% 89%; + --foreground: 200 50% 3%; + } + + @media (prefers-color-scheme: dark) { + :root { + --background: 200 50% 3%; + --btn-background: 200 10% 9%; + --btn-background-hover: 200 10% 12%; + --foreground: 200 20% 96%; + } + } +} + +@layer base { + * { + @apply border-foreground/20; + } +} + +.animate-in { + animation: animateIn 0.3s ease 0.15s both; +} + +@keyframes animateIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} diff --git a/apps/database-new/app/layout.tsx b/apps/database-new/app/layout.tsx new file mode 100644 index 00000000000..1723001b661 --- /dev/null +++ b/apps/database-new/app/layout.tsx @@ -0,0 +1,22 @@ +import { GeistSans } from 'geist/font' +import './globals.css' + +const defaultUrl = process.env.VERCEL_URL + ? `https://${process.env.VERCEL_URL}` + : 'http://localhost:3000' + +export const metadata = { + metadataBase: new URL(defaultUrl), + title: 'Next.js and Supabase Starter Kit', + description: 'The fastest way to build apps with Next.js and Supabase', +} + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + +
{children}
+ + + ) +} diff --git a/apps/database-new/app/login/page.tsx b/apps/database-new/app/login/page.tsx new file mode 100644 index 00000000000..fb9b7364ec9 --- /dev/null +++ b/apps/database-new/app/login/page.tsx @@ -0,0 +1,112 @@ +import Link from 'next/link' +import { headers, cookies } from 'next/headers' +import { createClient } from '@/utils/supabase/server' +import { redirect } from 'next/navigation' + +export default function Login({ searchParams }: { searchParams: { message: string } }) { + const signIn = async (formData: FormData) => { + 'use server' + + const email = formData.get('email') as string + const password = formData.get('password') as string + const cookieStore = cookies() + const supabase = createClient(cookieStore) + + const { error } = await supabase.auth.signInWithPassword({ + email, + password, + }) + + if (error) { + return redirect('/login?message=Could not authenticate user') + } + + return redirect('/') + } + + const signUp = async (formData: FormData) => { + 'use server' + + const origin = headers().get('origin') + const email = formData.get('email') as string + const password = formData.get('password') as string + const cookieStore = cookies() + const supabase = createClient(cookieStore) + + const { error } = await supabase.auth.signUp({ + email, + password, + options: { + emailRedirectTo: `${origin}/auth/callback`, + }, + }) + + if (error) { + return redirect('/login?message=Could not authenticate user') + } + + return redirect('/login?message=Check email to continue sign in process') + } + + return ( +
+ + + + {' '} + Back + + +
+ + + + + + + {searchParams?.message && ( +

+ {searchParams.message} +

+ )} +
+
+ ) +} diff --git a/apps/database-new/app/opengraph-image.png b/apps/database-new/app/opengraph-image.png new file mode 100644 index 00000000000..57595e662c3 Binary files /dev/null and b/apps/database-new/app/opengraph-image.png differ diff --git a/apps/database-new/app/page.tsx b/apps/database-new/app/page.tsx new file mode 100644 index 00000000000..01aa7f0d420 --- /dev/null +++ b/apps/database-new/app/page.tsx @@ -0,0 +1,57 @@ +import DeployButton from '../components/DeployButton' +import AuthButton from '../components/AuthButton' +import { createClient } from '@/utils/supabase/server' +import ConnectSupabaseSteps from '@/components/ConnectSupabaseSteps' +import SignUpUserSteps from '@/components/SignUpUserSteps' +import Header from '@/components/Header' +import { cookies } from 'next/headers' + +export default async function Index() { + const cookieStore = cookies() + + const canInitSupabaseClient = () => { + // This function is just for the interactive tutorial. + // Feel free to remove it once you have Supabase connected. + try { + createClient(cookieStore) + return true + } catch (e) { + return false + } + } + + const isSupabaseConnected = canInitSupabaseClient() + + return ( +
+ + +
+
+
+

Next steps

+ {isSupabaseConnected ? : } +
+
+ + +
+ ) +} diff --git a/apps/database-new/app/twitter-image.png b/apps/database-new/app/twitter-image.png new file mode 100644 index 00000000000..57595e662c3 Binary files /dev/null and b/apps/database-new/app/twitter-image.png differ diff --git a/apps/database-new/components/AuthButton.tsx b/apps/database-new/components/AuthButton.tsx new file mode 100644 index 00000000000..6e16b474ed3 --- /dev/null +++ b/apps/database-new/components/AuthButton.tsx @@ -0,0 +1,40 @@ +import { createClient } from '@/utils/supabase/server' +import Link from 'next/link' +import { cookies } from 'next/headers' +import { redirect } from 'next/navigation' + +export default async function AuthButton() { + const cookieStore = cookies() + const supabase = createClient(cookieStore) + + const { + data: { user }, + } = await supabase.auth.getUser() + + const signOut = async () => { + 'use server' + + const cookieStore = cookies() + const supabase = createClient(cookieStore) + await supabase.auth.signOut() + return redirect('/login') + } + + return user ? ( +
+ Hey, {user.email}! +
+ +
+
+ ) : ( + + Login + + ) +} diff --git a/apps/database-new/components/Code.tsx b/apps/database-new/components/Code.tsx new file mode 100644 index 00000000000..312d04ab8e2 --- /dev/null +++ b/apps/database-new/components/Code.tsx @@ -0,0 +1,58 @@ +'use client' + +import { useState } from 'react' + +const CopyIcon = () => ( + + + + +) + +const CheckIcon = () => ( + + + +) + +export default function Code({ code }: { code: string }) { + const [icon, setIcon] = useState(CopyIcon) + + const copy = async () => { + await navigator?.clipboard?.writeText(code) + setIcon(CheckIcon) + setTimeout(() => setIcon(CopyIcon), 2000) + } + + return ( +
+      
+      {code}
+    
+ ) +} diff --git a/apps/database-new/components/ConnectSupabaseSteps.tsx b/apps/database-new/components/ConnectSupabaseSteps.tsx new file mode 100644 index 00000000000..5a15faa5c62 --- /dev/null +++ b/apps/database-new/components/ConnectSupabaseSteps.tsx @@ -0,0 +1,59 @@ +import Step from './Step' + +export default function ConnectSupabaseSteps() { + return ( +
    + +

    + Head over to{' '} + + database.new + {' '} + and create a new Supabase project. +

    +
    + + +

    + Rename the{' '} + + .env.example + {' '} + file in your Next.js app to{' '} + + .env.local + {' '} + and populate with values from{' '} + + your Supabase project's API Settings + + . +

    +
    + + +

    + You may need to quit your Next.js development server and run{' '} + + npm run dev + {' '} + again to load the new environment variables. +

    +
    + + +

    You may need to refresh the page for Next.js to load the new environment variables.

    +
    +
+ ) +} diff --git a/apps/database-new/components/DeployButton.tsx b/apps/database-new/components/DeployButton.tsx new file mode 100644 index 00000000000..3ed637059b4 --- /dev/null +++ b/apps/database-new/components/DeployButton.tsx @@ -0,0 +1,15 @@ +export default function DeployButton() { + return ( + + + + + Deploy to Vercel + + ) +} diff --git a/apps/database-new/components/Header.tsx b/apps/database-new/components/Header.tsx new file mode 100644 index 00000000000..50e63d53e48 --- /dev/null +++ b/apps/database-new/components/Header.tsx @@ -0,0 +1,44 @@ +import NextLogo from './NextLogo' +import SupabaseLogo from './SupabaseLogo' + +export default function Header() { + return ( +
+
+ + + + + + + +
+

Supabase and Next.js Starter Template

+

+ The fastest way to build apps with{' '} + + Supabase + {' '} + and{' '} + + Next.js + +

+
+
+ ) +} diff --git a/apps/database-new/components/NextLogo.tsx b/apps/database-new/components/NextLogo.tsx new file mode 100644 index 00000000000..9e9c92f49ae --- /dev/null +++ b/apps/database-new/components/NextLogo.tsx @@ -0,0 +1,40 @@ +export default function NextLogo() { + return ( + + + + + + + + + + + ) +} diff --git a/apps/database-new/components/SignUpUserSteps.tsx b/apps/database-new/components/SignUpUserSteps.tsx new file mode 100644 index 00000000000..c5c28d14b2d --- /dev/null +++ b/apps/database-new/components/SignUpUserSteps.tsx @@ -0,0 +1,112 @@ +import Link from 'next/link' +import Step from './Step' +import Code from '@/components/Code' + +const create = ` +create table notes ( + id serial primary key, + title text +); + +insert into notes(title) +values + ('Today I created a Supabase project.'), + ('I added some data and queried it from Next.js.'), + ('It was awesome!'); +`.trim() + +const server = ` +import { createClient } from '@/utils/supabase/server' +import { cookies } from 'next/headers' + +export default async function Page() { + const cookieStore = cookies() + const supabase = createClient(cookieStore) + const { data: notes } = await supabase.from('notes').select() + + return
{JSON.stringify(notes, null, 2)}
+} +`.trim() + +const client = ` +'use client' + +import { createClient } from '@/utils/supabase/client' +import { useEffect, useState } from 'react' + +export default function Page() { + const [notes, setNotes] = useState(null) + const supabase = createClient() + + useEffect(() => { + const getData = async () => { + const { data } = await supabase.from('notes').select() + setNotes(data) + } + getData() + }, []) + + return
{JSON.stringify(notes, null, 2)}
+} +`.trim() + +export default function SignUpUserSteps() { + return ( +
    + +

    + Head over to the{' '} + + Login + {' '} + page and sign up your first user. It's okay if this is just you for now. Your awesome idea + will have plenty of users later! +

    +
    + + +

    + Head over to the{' '} + + Table Editor + {' '} + for your Supabase project to create a table and insert some example data. If you're stuck + for creativity, you can copy and paste the following into the{' '} + + SQL Editor + {' '} + and click RUN! +

    + +
    + + +

    + To create a Supabase client and query data from an Async Server Component, create a new + page.tsx file at{' '} + + /app/notes/page.tsx + {' '} + and add the following. +

    + +

    Alternatively, you can use a Client Component.

    + +
    + + +

    You're ready to launch your product to the world! 🚀

    +
    +
+ ) +} diff --git a/apps/database-new/components/Step.tsx b/apps/database-new/components/Step.tsx new file mode 100644 index 00000000000..6702a02964b --- /dev/null +++ b/apps/database-new/components/Step.tsx @@ -0,0 +1,14 @@ +export default function Step({ title, children }: { title: string; children: React.ReactNode }) { + return ( +
  • + + +
    {children}
    +
  • + ) +} diff --git a/apps/database-new/components/SupabaseLogo.tsx b/apps/database-new/components/SupabaseLogo.tsx new file mode 100644 index 00000000000..7d7dbe8207f --- /dev/null +++ b/apps/database-new/components/SupabaseLogo.tsx @@ -0,0 +1,102 @@ +export default function SupabaseLogo() { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/apps/database-new/middleware.ts b/apps/database-new/middleware.ts new file mode 100644 index 00000000000..25571510874 --- /dev/null +++ b/apps/database-new/middleware.ts @@ -0,0 +1,25 @@ +import { NextResponse, type NextRequest } from 'next/server' +import { createClient } from '@/utils/supabase/middleware' + +export async function middleware(request: NextRequest) { + try { + // This `try/catch` block is only here for the interactive tutorial. + // Feel free to remove once you have Supabase connected. + const { supabase, response } = createClient(request) + + // Refresh session if expired - required for Server Components + // https://supabase.com/docs/guides/auth/auth-helpers/nextjs#managing-session-with-middleware + await supabase.auth.getSession() + + return response + } catch (e) { + // If you are here, a Supabase client could not be created! + // This is likely because you have not set up environment variables. + // Check out http://localhost:3000 for Next Steps. + return NextResponse.next({ + request: { + headers: request.headers, + }, + }) + } +} diff --git a/apps/database-new/next.config.js b/apps/database-new/next.config.js new file mode 100644 index 00000000000..950e2f42ec3 --- /dev/null +++ b/apps/database-new/next.config.js @@ -0,0 +1,8 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + experimental: { + serverActions: true, + }, +} + +module.exports = nextConfig diff --git a/apps/database-new/package.json b/apps/database-new/package.json new file mode 100644 index 00000000000..abd2e60f222 --- /dev/null +++ b/apps/database-new/package.json @@ -0,0 +1,25 @@ +{ + "private": true, + "scripts": { + "dev": "next dev --port 3002", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "@supabase/ssr": "latest", + "@supabase/supabase-js": "latest", + "autoprefixer": "10.4.15", + "geist": "^1.0.0", + "next": "^13.5.3", + "postcss": "8.4.29", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "tailwindcss": "3.3.3", + "typescript": "^5.2.2" + }, + "devDependencies": { + "@types/node": "^18.11.9", + "@types/react": "^18.2.24", + "encoding": "^0.1.13" + } +} diff --git a/apps/database-new/postcss.config.js b/apps/database-new/postcss.config.js new file mode 100644 index 00000000000..33ad091d26d --- /dev/null +++ b/apps/database-new/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/apps/database-new/tailwind.config.js b/apps/database-new/tailwind.config.js new file mode 100644 index 00000000000..bd94e9ca9bc --- /dev/null +++ b/apps/database-new/tailwind.config.js @@ -0,0 +1,17 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ['./app/**/*.{js,ts,jsx,tsx,mdx}', './components/**/*.{js,ts,jsx,tsx,mdx}'], + theme: { + extend: { + colors: { + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + btn: { + background: 'hsl(var(--btn-background))', + 'background-hover': 'hsl(var(--btn-background-hover))', + }, + }, + }, + }, + plugins: [], +} diff --git a/apps/database-new/tsconfig.json b/apps/database-new/tsconfig.json new file mode 100644 index 00000000000..e06a4454ab0 --- /dev/null +++ b/apps/database-new/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/apps/database-new/utils/supabase/client.ts b/apps/database-new/utils/supabase/client.ts new file mode 100644 index 00000000000..5456942560c --- /dev/null +++ b/apps/database-new/utils/supabase/client.ts @@ -0,0 +1,7 @@ +import { createBrowserClient } from '@supabase/ssr' + +export const createClient = () => + createBrowserClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! + ) diff --git a/apps/database-new/utils/supabase/middleware.ts b/apps/database-new/utils/supabase/middleware.ts new file mode 100644 index 00000000000..3365525ed6d --- /dev/null +++ b/apps/database-new/utils/supabase/middleware.ts @@ -0,0 +1,61 @@ +import { createServerClient, type CookieOptions } from '@supabase/ssr' +import { type NextRequest, NextResponse } from 'next/server' + +export const createClient = (request: NextRequest) => { + // Create an unmodified response + let response = NextResponse.next({ + request: { + headers: request.headers, + }, + }) + + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + return request.cookies.get(name)?.value + }, + set(name: string, value: string, options: CookieOptions) { + // If the cookie is updated, update the cookies for the request and response + request.cookies.set({ + name, + value, + ...options, + }) + response = NextResponse.next({ + request: { + headers: request.headers, + }, + }) + response.cookies.set({ + name, + value, + ...options, + }) + }, + remove(name: string, options: CookieOptions) { + // If the cookie is removed, update the cookies for the request and response + request.cookies.set({ + name, + value: '', + ...options, + }) + response = NextResponse.next({ + request: { + headers: request.headers, + }, + }) + response.cookies.set({ + name, + value: '', + ...options, + }) + }, + }, + } + ) + + return { supabase, response } +} diff --git a/apps/database-new/utils/supabase/server.ts b/apps/database-new/utils/supabase/server.ts new file mode 100644 index 00000000000..0edfaa0df8d --- /dev/null +++ b/apps/database-new/utils/supabase/server.ts @@ -0,0 +1,34 @@ +import { createServerClient, type CookieOptions } from '@supabase/ssr' +import { cookies } from 'next/headers' + +export const createClient = (cookieStore: ReturnType) => { + return createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + return cookieStore.get(name)?.value + }, + set(name: string, value: string, options: CookieOptions) { + try { + cookieStore.set({ name, value, ...options }) + } catch (error) { + // The `set` method was called from a Server Component. + // This can be ignored if you have middleware refreshing + // user sessions. + } + }, + remove(name: string, options: CookieOptions) { + try { + cookieStore.set({ name, value: '', ...options }) + } catch (error) { + // The `delete` method was called from a Server Component. + // This can be ignored if you have middleware refreshing + // user sessions. + } + }, + }, + } + ) +} diff --git a/package-lock.json b/package-lock.json index ddef18ad0de..e66da846f44 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,97 @@ "npm": ">=9.0.0 <10.0.0" } }, + "apps/database-new": { + "dependencies": { + "@supabase/ssr": "latest", + "@supabase/supabase-js": "latest", + "autoprefixer": "10.4.15", + "geist": "^1.0.0", + "next": "^13.5.3", + "postcss": "8.4.29", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "tailwindcss": "3.3.3", + "typescript": "^5.2.2" + }, + "devDependencies": { + "@types/node": "^18.11.9", + "@types/react": "^18.2.24", + "encoding": "^0.1.13" + } + }, + "apps/database-new/node_modules/@types/node": { + "version": "18.18.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.9.tgz", + "integrity": "sha512-0f5klcuImLnG4Qreu9hPj/rEfFq6YRc5n2mAjSsH+ec/mJL+3voBH0+8T7o8RpFjH7ovc+TRsL/c7OYIQsPTfQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "apps/database-new/node_modules/autoprefixer": { + "version": "10.4.15", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz", + "integrity": "sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001520", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "apps/database-new/node_modules/postcss": { + "version": "8.4.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", + "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, "apps/docs": { "version": "0.0.0", "dependencies": { @@ -10259,6 +10350,18 @@ "resolved": "https://registry.npmjs.org/@supabase/shared-types/-/shared-types-0.1.51.tgz", "integrity": "sha512-ZCm3sdxFwFDIOakciAH+or1gWQ6SKqiSWmmejsUCyH5QfMl4ngFc6hZcNEky5+NJ5wI7YtukUpvKihNVR0iNSg==" }, + "node_modules/@supabase/ssr": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/@supabase/ssr/-/ssr-0.0.10.tgz", + "integrity": "sha512-eVs7+bNlff8Fd79x8K3Jbfpmf8P8QRA1Z6rUDN+fi4ReWvRBZyWOFfR6eqlsX6vTjvGgTiEqujFSkv2PYW5kbQ==", + "dependencies": { + "cookie": "^0.5.0", + "ramda": "^0.29.0" + }, + "peerDependencies": { + "@supabase/supabase-js": "^2.33.1" + } + }, "node_modules/@supabase/storage-js": { "version": "2.5.4", "resolved": "https://registry.npmjs.org/@supabase/storage-js/-/storage-js-2.5.4.tgz", @@ -11590,9 +11693,9 @@ "dev": true }, "node_modules/@types/react": { - "version": "18.2.24", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.24.tgz", - "integrity": "sha512-Ee0Jt4sbJxMu1iDcetZEIKQr99J1Zfb6D4F3qfUWoR1JpInkY1Wdg4WwCyBjL257D0+jGqSl1twBjV8iCaC0Aw==", + "version": "18.2.37", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.37.tgz", + "integrity": "sha512-RGAYMi2bhRgEXT3f4B92WTohopH6bIXw05FuGlmJEnv/omEn190+QYEIYxIAuIBdKgboYYdVved2p1AxZVQnaw==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -15234,7 +15337,6 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -16345,6 +16447,10 @@ "node": ">=12" } }, + "node_modules/database-new": { + "resolved": "apps/database-new", + "link": true + }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -17097,7 +17203,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "optional": true, + "devOptional": true, "dependencies": { "iconv-lite": "^0.6.2" } @@ -19321,6 +19427,14 @@ "node": ">=8" } }, + "node_modules/geist": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/geist/-/geist-1.1.0.tgz", + "integrity": "sha512-UwZH+ekwAt1T5XYlviFD+jUXFeRRawDDT8RtpJ//IHTPXlVIO6BCcZ8M0Pxg1K/FT3H8HLn3KJqMsPLHbo1HNg==", + "peerDependencies": { + "next": "^13.2 || ^14" + } + }, "node_modules/generate-password": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/generate-password/-/generate-password-1.7.0.tgz", @@ -31316,7 +31430,6 @@ "version": "0.29.0", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.29.0.tgz", "integrity": "sha512-BBea6L67bYLtdbOqfp8f58fPMqEwx0doL+pAi8TZyp2YWz8R9G8z9x75CZI8W+ftqhFHCpEX2cRnUUXK130iKA==", - "dev": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/ramda"