diff --git a/.prettierrc b/.prettierrc.json
similarity index 100%
rename from .prettierrc
rename to .prettierrc.json
diff --git a/apps/studio/pages/sign-in.tsx b/apps/studio/pages/sign-in.tsx
index 62f383d2777..9d7b294ca42 100644
--- a/apps/studio/pages/sign-in.tsx
+++ b/apps/studio/pages/sign-in.tsx
@@ -44,7 +44,7 @@ const SignInPage: NextPageWithLayout = () => {
- or
+ or
diff --git a/apps/ui-library/app/api/blocks/[slug]/route.ts b/apps/ui-library/app/api/blocks/[slug]/route.ts
new file mode 100644
index 00000000000..7c3db50abb5
--- /dev/null
+++ b/apps/ui-library/app/api/blocks/[slug]/route.ts
@@ -0,0 +1,126 @@
+import fs from 'fs'
+import { template } from 'lodash'
+import path from 'path'
+import * as prettier from 'prettier'
+import { type RegistryItem } from 'shadcn/schema'
+
+const SOCIAL_PROVIDERS = [
+ { label: 'Password', value: 'password' },
+ { label: 'Google', value: 'google' },
+ { label: 'Facebook', value: 'facebook' },
+ { label: 'Apple', value: 'apple' },
+ { label: 'Azure (Microsoft)', value: 'azure' },
+ { label: 'Twitter', value: 'twitter' },
+ { label: 'GitHub', value: 'github' },
+ { label: 'Gitlab', value: 'gitlab' },
+ { label: 'Bitbucket', value: 'bitbucket' },
+ { label: 'Discord', value: 'discord' },
+ { label: 'Figma', value: 'figma' },
+ { label: 'Kakao', value: 'kakao' },
+ { label: 'Keycloak', value: 'keycloak' },
+ { label: 'LinkedIn', value: 'linkedin' },
+ { label: 'Notion', value: 'notion' },
+ { label: 'Slack', value: 'slack' },
+ { label: 'Spotify', value: 'spotify' },
+ { label: 'Twitch', value: 'twitch' },
+ { label: 'WorkOS', value: 'workos' },
+ { label: 'Zoom', value: 'zoom' },
+]
+
+export async function GET(_request: Request, { params }: { params: Promise<{ slug: string }> }) {
+ try {
+ const slug = (await params).slug.replace('.json', '')
+ const parts = slug.split('-')
+
+ let [framework, ...authTypes] = parts
+
+ // Build block names
+ const passwordBlockName = `password-based-auth-${framework}`
+ const socialBlockName = `social-auth-${framework}`
+
+ const blocksDir = path.join(process.cwd(), 'public', 'r')
+
+ const blocks: RegistryItem[] = []
+ const imports: string[] = []
+ const components: string[] = []
+
+ const commonBlockPath = path.join(blocksDir, `common-auth-nextjs.json`)
+ const commonBlock: RegistryItem = JSON.parse(fs.readFileSync(commonBlockPath, 'utf-8'))
+ blocks.push(commonBlock)
+
+ if (authTypes.includes('password')) {
+ // Read the base auth block
+ const baseBlockPath = path.join(blocksDir, `${passwordBlockName}.json`)
+ if (!fs.existsSync(baseBlockPath)) {
+ return Response.json(
+ { error: `Base block not found: ${passwordBlockName}` },
+ { status: 404 }
+ )
+ }
+ const baseBlock: RegistryItem = JSON.parse(fs.readFileSync(baseBlockPath, 'utf-8'))
+ blocks.push(baseBlock)
+ imports.push(
+ "import { PasswordLoginForm } from '@/registry/default/blocks/password-based-auth-nextjs/components/password-login-form'"
+ )
+ components.push(' ')
+ if (authTypes.length > 1) {
+ components.push(
+ ``
+ )
+ }
+ }
+
+ for (let authType of authTypes) {
+ if (authType === 'password') {
+ // Already handled above
+ continue
+ }
+ const provider = SOCIAL_PROVIDERS.find((p) => p.value === authType)
+ if (!provider) {
+ return Response.json({ error: `Unknown auth type: ${authType}` }, { status: 400 })
+ }
+
+ const socialBlockPath = path.join(blocksDir, `${socialBlockName}.json`)
+ const socialBlock: RegistryItem = JSON.parse(fs.readFileSync(socialBlockPath, 'utf-8'))
+ blocks.push(socialBlock)
+ if (imports.find((imp) => imp.includes('SocialLoginButton')) === undefined) {
+ imports.push(
+ "import { SocialLoginButton } from '@/registry/default/blocks/social-auth-nextjs/components/social-login-button'"
+ )
+ }
+
+ components.push(
+ ` `
+ )
+ }
+
+ // Create combined block
+ const combinedBlock: RegistryItem = {
+ name: slug,
+ type: 'registry:block',
+ title: `Combined Auth with ${authTypes.join(', ')} for ${framework}`,
+ description: `Combined authentication flow with password-based auth and ${authTypes.join(', ')} social providers for ${framework}`,
+ registryDependencies: Array.from(
+ new Set(blocks.flatMap((b) => b.registryDependencies || []))
+ ),
+ dependencies: Array.from(new Set(blocks.flatMap((b) => b.dependencies || []))),
+ files: blocks.flatMap((b) => b.files || []),
+ }
+
+ const loginForm = combinedBlock.files?.find((f) => f.path.endsWith('app/auth/login/page.tsx'))
+ if (loginForm) {
+ const compiled = template(loginForm.content, { interpolate: /{?\/\*<%=(.+?)%> \*\/}?/g })
+ const templated = compiled({
+ imports: imports.join('\n'),
+ components: components.join(''),
+ })
+ const content = await prettier.format(templated, { parser: 'typescript' } as prettier.Options)
+ loginForm.content = content
+ }
+
+ return Response.json(combinedBlock, { status: 200 })
+ } catch (error) {
+ console.error('Error processing block request:', error)
+ return Response.json({ error: 'Internal server error' }, { status: 500 })
+ }
+}
diff --git a/apps/ui-library/components/command.tsx b/apps/ui-library/components/command.tsx
index 1956537604e..7814efccb07 100644
--- a/apps/ui-library/components/command.tsx
+++ b/apps/ui-library/components/command.tsx
@@ -28,7 +28,7 @@ export function Command({ name, highlight }: CommandCopyProps) {
}
const baseUrl = getBaseUrl()
- const componentPath = `${process.env.NEXT_PUBLIC_BASE_PATH ?? ''}/r/${name}.json`
+ const componentPath = `${process.env.NEXT_PUBLIC_BASE_PATH ?? ''}/api/blocks/${name}.json`
const commands: Record = {
npm: `npx shadcn@latest add ${baseUrl}${componentPath}`,
diff --git a/apps/ui-library/components/generated-auth-block-item.tsx b/apps/ui-library/components/generated-auth-block-item.tsx
new file mode 100644
index 00000000000..d6ddaa5340d
--- /dev/null
+++ b/apps/ui-library/components/generated-auth-block-item.tsx
@@ -0,0 +1,74 @@
+'use client'
+
+import { OpenInV0Button } from '@/components/open-in-v0-button'
+import { type Provider } from '@supabase/supabase-js'
+import dynamic from 'next/dynamic'
+import { useState } from 'react'
+import { Label_Shadcn_, Switch } from 'ui'
+
+//The dynamic import is to prevent the command component from being rendered on the server and cause hydration errors
+const Command = dynamic(() => import('./command').then((mod) => mod.Command), { ssr: false })
+
+interface BlockItemProps {
+ name: string
+}
+
+const PROVIDERS: { label: string; value: Provider | 'password' }[] = [
+ { label: 'Password', value: 'password' },
+ { label: 'Google', value: 'google' },
+ { label: 'Facebook', value: 'facebook' },
+ { label: 'Apple', value: 'apple' },
+ { label: 'Azure (Microsoft)', value: 'azure' },
+ { label: 'Twitter', value: 'twitter' },
+ { label: 'GitHub', value: 'github' },
+ { label: 'Gitlab', value: 'gitlab' },
+ { label: 'Bitbucket', value: 'bitbucket' },
+ { label: 'Discord', value: 'discord' },
+ { label: 'Figma', value: 'figma' },
+ { label: 'Kakao', value: 'kakao' },
+ { label: 'Keycloak', value: 'keycloak' },
+ { label: 'LinkedIn', value: 'linkedin' },
+ { label: 'Notion', value: 'notion' },
+ { label: 'Slack', value: 'slack' },
+ { label: 'Spotify', value: 'spotify' },
+ { label: 'Twitch', value: 'twitch' },
+ { label: 'WorkOS', value: 'workos' },
+ { label: 'Zoom', value: 'zoom' },
+]
+
+export const GeneratedAuthBlockItem = ({
+ name = 'social-auth-nextjs',
+}: {
+ name?: string
+ description?: string
+}) => {
+ const [selected, setSelected] = useState([])
+
+ const handleChange = (provider: string) => {
+ setSelected((prev: string[]) =>
+ prev.includes(provider) ? prev.filter((p) => p !== provider) : [...prev, provider]
+ )
+ }
+
+ const url = `nextjs-${selected.join('-')}`
+
+ return (
+
+
+ {PROVIDERS.map((provider) => (
+
+ handleChange(provider.value)}
+ className="mr-2"
+ />
+ {provider.label}
+
+ ))}
+
+
+
+
+
+ )
+}
diff --git a/apps/ui-library/components/mdx-components.tsx b/apps/ui-library/components/mdx-components.tsx
index ff192643d0b..f5cafc479a3 100644
--- a/apps/ui-library/components/mdx-components.tsx
+++ b/apps/ui-library/components/mdx-components.tsx
@@ -15,6 +15,7 @@ import { Callout } from './callout'
import { ComponentPreview } from './component-preview'
import { CopyButton } from './copy-button'
import { DualRealtimeChat } from './dual-realtime-chat'
+import { GeneratedAuthBlockItem } from './generated-auth-block-item'
import { RegistryBlock } from './registry-block'
import { StyleWrapper } from './style-wrapper'
import TanStackBeta from './tanstack-beta'
@@ -169,6 +170,7 @@ const components = {
/>
),
BlockItem,
+ GeneratedAuthBlockItem,
BlockPreview,
DualRealtimeChat,
}
diff --git a/apps/ui-library/content/docs/nextjs/generated-auth.mdx b/apps/ui-library/content/docs/nextjs/generated-auth.mdx
new file mode 100644
index 00000000000..3f4750ea2be
--- /dev/null
+++ b/apps/ui-library/content/docs/nextjs/generated-auth.mdx
@@ -0,0 +1,44 @@
+---
+title: Generated Authentication
+description: Generated authentication block for Next.js
+---
+
+
+ Select which providers to enable below. The generated URL will call the API route for block
+ generation.
+
+
+## Installation
+
+Select which social providers you want to be added to the block.
+
+
+
+## Folder structure
+
+This block includes the [Supabase client](/ui/docs/nextjs/client). If you already have one installed, you can skip overwriting it.
+
+## Usage
+
+Once you install the block in your Next.js project, you'll get all the necessary pages and components to set up authentication flow with the specified providers.
+
+### Getting started
+
+After installing the block, you'll have the following environment variables in your `.env.local` file:
+
+```env
+NEXT_PUBLIC_SUPABASE_URL=
+NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY=
+```
+
+- If you're using supabase.com, you can find these values in the [Connect modal](https://supabase.com/dashboard/project/_?showConnect=true) under App Frameworks or in your project's [API settings](https://supabase.com/dashboard/project/_/settings/api).
+
+- If you're using a local instance of Supabase, you can find these values by running `supabase start` or `supabase status` (if you already have it running).
+
+## Further reading
+
+- [Social login](https://supabase.com/docs/guides/auth/social-login)
+- [Authentication error codes](https://supabase.com/docs/guides/auth/debugging/error-codes)
diff --git a/apps/ui-library/public/r/common-auth-nextjs.json b/apps/ui-library/public/r/common-auth-nextjs.json
new file mode 100644
index 00000000000..c23438f8695
--- /dev/null
+++ b/apps/ui-library/public/r/common-auth-nextjs.json
@@ -0,0 +1,68 @@
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "common-auth-nextjs",
+ "type": "registry:block",
+ "title": "Common Auth flow for Nextjs and Supabase",
+ "description": "Common Auth flow for Nextjs and Supabase",
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "registryDependencies": [
+ "button",
+ "card",
+ "input",
+ "label"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/app/auth/login/page.tsx",
+ "content": "import {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from '@/registry/default/components/ui/card'\n/*<%= imports %> */\n\nexport default function Page() {\n return (\n \n
\n
\n \n \n Login \n Sign in to your account to continue \n \n {/*<%= components %> */} \n \n
\n
\n
\n )\n}\n",
+ "type": "registry:page",
+ "target": "app/auth/login/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/app/auth/error/page.tsx",
+ "content": "import { Card, CardContent, CardHeader, CardTitle } from '@/registry/default/components/ui/card'\n\nexport default async function Page({ searchParams }: { searchParams: Promise<{ error: string }> }) {\n const params = await searchParams\n\n return (\n \n
\n
\n
\n \n Sorry, something went wrong. \n \n \n {params?.error ? (\n Code error: {params.error}
\n ) : (\n An unspecified error occurred.
\n )}\n \n \n
\n
\n
\n )\n}\n",
+ "type": "registry:page",
+ "target": "app/auth/error/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/app/protected/page.tsx",
+ "content": "import { redirect } from 'next/navigation'\n\nimport { LogoutButton } from '@/registry/default/blocks/password-based-auth-nextjs/components/logout-button'\nimport { createClient } from '@/registry/default/clients/nextjs/lib/supabase/server'\n\nexport default async function ProtectedPage() {\n const supabase = await createClient()\n\n const { data, error } = await supabase.auth.getClaims()\n if (error || !data?.claims) {\n redirect('/auth/login')\n }\n\n return (\n \n
\n Hello {data.claims.email} \n
\n
\n
\n )\n}\n",
+ "type": "registry:page",
+ "target": "app/protected/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/middleware.ts",
+ "content": "import { updateSession } from '@/registry/default/clients/nextjs/lib/supabase/middleware'\nimport { type NextRequest } from 'next/server'\n\nexport async function middleware(request: NextRequest) {\n return await updateSession(request)\n}\n\nexport const config = {\n matcher: [\n /*\n * Match all request paths except for the ones starting with:\n * - _next/static (static files)\n * - _next/image (image optimization files)\n * - favicon.ico (favicon file)\n * Feel free to modify this pattern to include more paths.\n */\n '/((?!_next/static|_next/image|favicon.ico|.*\\\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',\n ],\n}\n",
+ "type": "registry:file",
+ "target": "middleware.ts"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/components/logout-button.tsx",
+ "content": "'use client'\n\nimport { createClient } from '@/registry/default/clients/nextjs/lib/supabase/client'\nimport { Button } from '@/registry/default/components/ui/button'\nimport { useRouter } from 'next/navigation'\n\nexport function LogoutButton() {\n const router = useRouter()\n\n const logout = async () => {\n const supabase = createClient()\n await supabase.auth.signOut()\n router.push('/auth/login')\n }\n\n return Logout \n}\n",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/client.ts",
+ "content": "import { createBrowserClient } from '@supabase/ssr'\n\nexport function createClient() {\n return createBrowserClient(\n process.env.NEXT_PUBLIC_SUPABASE_URL!,\n process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY!\n )\n}\n",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/middleware.ts",
+ "content": "import { createServerClient } from '@supabase/ssr'\nimport { NextResponse, type NextRequest } from 'next/server'\n\nexport async function updateSession(request: NextRequest) {\n let supabaseResponse = NextResponse.next({\n request,\n })\n\n // With Fluid compute, don't put this client in a global environment\n // variable. Always create a new one on each request.\n const supabase = createServerClient(\n process.env.NEXT_PUBLIC_SUPABASE_URL!,\n process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY!,\n {\n cookies: {\n getAll() {\n return request.cookies.getAll()\n },\n setAll(cookiesToSet) {\n cookiesToSet.forEach(({ name, value }) => request.cookies.set(name, value))\n supabaseResponse = NextResponse.next({\n request,\n })\n cookiesToSet.forEach(({ name, value, options }) =>\n supabaseResponse.cookies.set(name, value, options)\n )\n },\n },\n }\n )\n\n // Do not run code between createServerClient and\n // supabase.auth.getClaims(). A simple mistake could make it very hard to debug\n // issues with users being randomly logged out.\n\n // IMPORTANT: If you remove getClaims() and you use server-side rendering\n // with the Supabase client, your users may be randomly logged out.\n const { data } = await supabase.auth.getClaims()\n const user = data?.claims\n\n if (\n !user &&\n !request.nextUrl.pathname.startsWith('/login') &&\n !request.nextUrl.pathname.startsWith('/auth')\n ) {\n // no user, potentially respond by redirecting the user to the login page\n const url = request.nextUrl.clone()\n url.pathname = '/auth/login'\n return NextResponse.redirect(url)\n }\n\n // IMPORTANT: You *must* return the supabaseResponse object as it is.\n // If you're creating a new response object with NextResponse.next() make sure to:\n // 1. Pass the request in it, like so:\n // const myNewResponse = NextResponse.next({ request })\n // 2. Copy over the cookies, like so:\n // myNewResponse.cookies.setAll(supabaseResponse.cookies.getAll())\n // 3. Change the myNewResponse object to fit your needs, but avoid changing\n // the cookies!\n // 4. Finally:\n // return myNewResponse\n // If this is not done, you may be causing the browser and server to go out\n // of sync and terminate the user's session prematurely!\n\n return supabaseResponse\n}\n",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/server.ts",
+ "content": "import { createServerClient } from '@supabase/ssr'\nimport { cookies } from 'next/headers'\n\n/**\n * If using Fluid compute: Don't put this client in a global variable. Always create a new client within each\n * function when using it.\n */\nexport async function createClient() {\n const cookieStore = await cookies()\n\n return createServerClient(\n process.env.NEXT_PUBLIC_SUPABASE_URL!,\n process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY!,\n {\n cookies: {\n getAll() {\n return cookieStore.getAll()\n },\n setAll(cookiesToSet) {\n try {\n cookiesToSet.forEach(({ name, value, options }) =>\n cookieStore.set(name, value, options)\n )\n } catch {\n // The `setAll` method was called from a Server Component.\n // This can be ignored if you have middleware refreshing\n // user sessions.\n }\n },\n },\n }\n )\n}\n",
+ "type": "registry:lib"
+ }
+ ],
+ "envVars": {
+ "NEXT_PUBLIC_SUPABASE_URL": "",
+ "NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ },
+ "docs": "You'll need to set the following environment variables in your project: `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY`."
+}
\ No newline at end of file
diff --git a/apps/ui-library/public/r/password-based-auth-nextjs.json b/apps/ui-library/public/r/password-based-auth-nextjs.json
index f5c48585d09..e897d272c36 100644
--- a/apps/ui-library/public/r/password-based-auth-nextjs.json
+++ b/apps/ui-library/public/r/password-based-auth-nextjs.json
@@ -15,12 +15,6 @@
"label"
],
"files": [
- {
- "path": "registry/default/blocks/password-based-auth-nextjs/app/auth/login/page.tsx",
- "content": "import { LoginForm } from '@/registry/default/blocks/password-based-auth-nextjs/components/login-form'\n\nexport default function Page() {\n return (\n \n )\n}\n",
- "type": "registry:page",
- "target": "app/auth/login/page.tsx"
- },
{
"path": "registry/default/blocks/password-based-auth-nextjs/app/auth/error/page.tsx",
"content": "import { Card, CardContent, CardHeader, CardTitle } from '@/registry/default/components/ui/card'\n\nexport default async function Page({ searchParams }: { searchParams: Promise<{ error: string }> }) {\n const params = await searchParams\n\n return (\n \n
\n
\n
\n \n Sorry, something went wrong. \n \n \n {params?.error ? (\n Code error: {params.error}
\n ) : (\n An unspecified error occurred.
\n )}\n \n \n
\n
\n
\n )\n}\n",
@@ -39,14 +33,9 @@
"type": "registry:page",
"target": "app/auth/confirm/route.ts"
},
- {
- "path": "registry/default/blocks/password-based-auth-nextjs/components/login-form.tsx",
- "content": "'use client'\n\nimport { cn } from '@/lib/utils'\nimport { createClient } from '@/registry/default/clients/nextjs/lib/supabase/client'\nimport { Button } from '@/registry/default/components/ui/button'\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from '@/registry/default/components/ui/card'\nimport { Input } from '@/registry/default/components/ui/input'\nimport { Label } from '@/registry/default/components/ui/label'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { useState } from 'react'\n\nexport function LoginForm({ className, ...props }: React.ComponentPropsWithoutRef<'div'>) {\n const [email, setEmail] = useState('')\n const [password, setPassword] = useState('')\n const [error, setError] = useState(null)\n const [isLoading, setIsLoading] = useState(false)\n const router = useRouter()\n\n const handleLogin = async (e: React.FormEvent) => {\n e.preventDefault()\n const supabase = createClient()\n setIsLoading(true)\n setError(null)\n\n try {\n const { error } = await supabase.auth.signInWithPassword({\n email,\n password,\n })\n if (error) throw error\n // Update this route to redirect to an authenticated route. The user already has an active session.\n router.push('/protected')\n } catch (error: unknown) {\n setError(error instanceof Error ? error.message : 'An error occurred')\n } finally {\n setIsLoading(false)\n }\n }\n\n return (\n \n
\n \n Login \n Enter your email below to login to your account \n \n \n \n \n \n
\n )\n}\n",
- "type": "registry:component"
- },
{
"path": "registry/default/blocks/password-based-auth-nextjs/middleware.ts",
- "content": "import { updateSession } from '@/registry/default/clients/nextjs/lib/supabase/middleware'\nimport { type NextRequest } from 'next/server'\n\nexport async function middleware(request: NextRequest) {\n return await updateSession(request)\n}\n\nexport const config = {\n matcher: [\n /*\n * Match all request paths except:\n * - _next/static (static files)\n * - _next/image (image optimization files)\n * - favicon.ico (favicon file)\n * - images - .svg, .png, .jpg, .jpeg, .gif, .webp\n * Feel free to modify this pattern to include more paths.\n */\n '/((?!_next/static|_next/image|favicon.ico|.*\\\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',\n ],\n}\n",
+ "content": "import { updateSession } from '@/registry/default/clients/nextjs/lib/supabase/middleware'\nimport { type NextRequest } from 'next/server'\n\nexport async function middleware(request: NextRequest) {\n return await updateSession(request)\n}\n\nexport const config = {\n matcher: [\n /*\n * Match all request paths except for the ones starting with:\n * - _next/static (static files)\n * - _next/image (image optimization files)\n * - favicon.ico (favicon file)\n * Feel free to modify this pattern to include more paths.\n */\n '/((?!_next/static|_next/image|favicon.ico|.*\\\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',\n ],\n}\n",
"type": "registry:file",
"target": "middleware.ts"
},
@@ -94,6 +83,11 @@
"content": "'use client'\n\nimport { createClient } from '@/registry/default/clients/nextjs/lib/supabase/client'\nimport { Button } from '@/registry/default/components/ui/button'\nimport { useRouter } from 'next/navigation'\n\nexport function LogoutButton() {\n const router = useRouter()\n\n const logout = async () => {\n const supabase = createClient()\n await supabase.auth.signOut()\n router.push('/auth/login')\n }\n\n return Logout \n}\n",
"type": "registry:component"
},
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/components/password-login-form.tsx",
+ "content": "'use client'\n\nimport { createClient } from '@/registry/default/clients/nextjs/lib/supabase/client'\nimport { Button } from '@/registry/default/components/ui/button'\nimport { Input } from '@/registry/default/components/ui/input'\nimport { Label } from '@/registry/default/components/ui/label'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport { useState } from 'react'\n\nexport function PasswordLoginForm() {\n const [email, setEmail] = useState('')\n const [password, setPassword] = useState('')\n const [error, setError] = useState(null)\n const [isLoading, setIsLoading] = useState(false)\n const router = useRouter()\n\n const handleLogin = async (e: React.FormEvent) => {\n e.preventDefault()\n const supabase = createClient()\n setIsLoading(true)\n setError(null)\n\n try {\n const { error } = await supabase.auth.signInWithPassword({\n email,\n password,\n })\n if (error) throw error\n // Update this route to redirect to an authenticated route. The user already has an active session.\n router.push('/protected')\n } catch (error: unknown) {\n setError(error instanceof Error ? error.message : 'An error occurred')\n } finally {\n setIsLoading(false)\n }\n }\n\n return (\n \n )\n}\n",
+ "type": "registry:component"
+ },
{
"path": "registry/default/clients/nextjs/lib/supabase/client.ts",
"content": "import { createBrowserClient } from '@supabase/ssr'\n\nexport function createClient() {\n return createBrowserClient(\n process.env.NEXT_PUBLIC_SUPABASE_URL!,\n process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY!\n )\n}\n",
diff --git a/apps/ui-library/public/r/registry.json b/apps/ui-library/public/r/registry.json
new file mode 100644
index 00000000000..70522f5bc0c
--- /dev/null
+++ b/apps/ui-library/public/r/registry.json
@@ -0,0 +1,1795 @@
+{
+ "$schema": "https://ui.shadcn.com/schema/registry.json",
+ "name": "Supabase UI Library",
+ "homepage": "https://supabase.com/ui",
+ "items": [
+ {
+ "name": "common-auth-nextjs",
+ "type": "registry:block",
+ "title": "Common Auth flow for Nextjs and Supabase",
+ "description": "Common Auth flow for Nextjs and Supabase",
+ "registryDependencies": [
+ "button",
+ "card",
+ "input",
+ "label"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/app/auth/login/page.tsx",
+ "type": "registry:page",
+ "target": "app/auth/login/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/app/auth/error/page.tsx",
+ "type": "registry:page",
+ "target": "app/auth/error/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/app/protected/page.tsx",
+ "type": "registry:page",
+ "target": "app/protected/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/middleware.ts",
+ "type": "registry:file",
+ "target": "middleware.ts"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/components/logout-button.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/middleware.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "NEXT_PUBLIC_SUPABASE_URL": "",
+ "NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "name": "password-based-auth-nextjs",
+ "type": "registry:block",
+ "title": "Password Based Auth flow for Nextjs and Supabase",
+ "description": "Password Based Auth flow for Nextjs and Supabase",
+ "registryDependencies": [
+ "button",
+ "card",
+ "input",
+ "label"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/app/auth/error/page.tsx",
+ "type": "registry:page",
+ "target": "app/auth/error/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/app/protected/page.tsx",
+ "type": "registry:page",
+ "target": "app/protected/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/app/auth/confirm/route.ts",
+ "type": "registry:page",
+ "target": "app/auth/confirm/route.ts"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/middleware.ts",
+ "type": "registry:file",
+ "target": "middleware.ts"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/app/auth/sign-up/page.tsx",
+ "type": "registry:page",
+ "target": "app/auth/sign-up/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/app/auth/sign-up-success/page.tsx",
+ "type": "registry:page",
+ "target": "app/auth/sign-up-success/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/components/sign-up-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/app/auth/forgot-password/page.tsx",
+ "type": "registry:page",
+ "target": "app/auth/forgot-password/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/app/auth/update-password/page.tsx",
+ "type": "registry:page",
+ "target": "app/auth/update-password/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/components/forgot-password-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/components/update-password-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/components/logout-button.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/components/password-login-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/middleware.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "NEXT_PUBLIC_SUPABASE_URL": "",
+ "NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "name": "password-based-auth-react",
+ "type": "registry:block",
+ "title": "Password Based Auth flow for React and Supabase",
+ "description": "Password Based Auth flow for React and Supabase",
+ "registryDependencies": [
+ "button",
+ "card",
+ "input",
+ "label"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/password-based-auth-react/components/login-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-react/components/sign-up-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-react/components/forgot-password-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-react/components/update-password-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/clients/react/lib/supabase/client.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "dependencies": [
+ "@supabase/supabase-js@latest"
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "name": "password-based-auth-react-router",
+ "type": "registry:block",
+ "title": "Password Based Auth flow for React Router and Supabase",
+ "description": "Password Based Auth flow for React Router and Supabase",
+ "registryDependencies": [
+ "button",
+ "card",
+ "input",
+ "label"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@react-router/dev@latest",
+ "@react-router/fs-routes@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/password-based-auth-react-router/app/routes/auth.confirm.tsx",
+ "type": "registry:file",
+ "target": "app/routes/auth.confirm.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-react-router/app/routes/auth.error.tsx",
+ "type": "registry:file",
+ "target": "app/routes/auth.error.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-react-router/app/routes/forgot-password.tsx",
+ "type": "registry:file",
+ "target": "app/routes/forgot-password.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-react-router/app/routes/login.tsx",
+ "type": "registry:file",
+ "target": "app/routes/login.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-react-router/app/routes/logout.tsx",
+ "type": "registry:file",
+ "target": "app/routes/logout.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-react-router/app/routes/protected.tsx",
+ "type": "registry:file",
+ "target": "app/routes/protected.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-react-router/app/routes/sign-up.tsx",
+ "type": "registry:file",
+ "target": "app/routes/sign-up.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-react-router/app/routes/update-password.tsx",
+ "type": "registry:file",
+ "target": "app/routes/update-password.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-react-router/app/routes.ts",
+ "type": "registry:file",
+ "target": "app/routes.ts"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "name": "password-based-auth-tanstack",
+ "type": "registry:block",
+ "title": "Password Based Auth flow for tanstack and Supabase",
+ "description": "Password Based Auth flow for tanstack and Supabase",
+ "registryDependencies": [
+ "button",
+ "card",
+ "input",
+ "label"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/routes/login.tsx",
+ "type": "registry:file",
+ "target": "routes/login.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/routes/auth/error.tsx",
+ "type": "registry:file",
+ "target": "routes/auth/error.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/routes/_protected.tsx",
+ "type": "registry:file",
+ "target": "routes/_protected.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/routes/_protected/protected.tsx",
+ "type": "registry:file",
+ "target": "routes/_protected/protected.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/routes/auth/confirm.ts",
+ "type": "registry:file",
+ "target": "routes/auth/confirm.ts"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/components/login-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/routes/sign-up.tsx",
+ "type": "registry:file",
+ "target": "routes/sign-up.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/routes/sign-up-success.tsx",
+ "type": "registry:file",
+ "target": "routes/sign-up-success.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/components/sign-up-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/routes/forgot-password.tsx",
+ "type": "registry:file",
+ "target": "routes/forgot-password.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/routes/update-password.tsx",
+ "type": "registry:file",
+ "target": "routes/update-password.tsx"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/components/forgot-password-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/components/update-password-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-tanstack/lib/supabase/fetch-user-server-fn.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "name": "social-auth-nextjs",
+ "type": "registry:block",
+ "title": "Social Auth flow for Nextjs and Supabase",
+ "description": "Social Auth flow for Nextjs and Supabase",
+ "registryDependencies": [
+ "button",
+ "card"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/social-auth-nextjs/app/auth/error/page.tsx",
+ "type": "registry:page",
+ "target": "app/auth/error/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-nextjs/app/protected/page.tsx",
+ "type": "registry:page",
+ "target": "app/protected/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-nextjs/app/auth/oauth/route.ts",
+ "type": "registry:page",
+ "target": "app/auth/oauth/route.ts"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-nextjs/middleware.ts",
+ "type": "registry:file",
+ "target": "middleware.ts"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-nextjs/components/logout-button.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-nextjs/components/social-login-button.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/middleware.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "NEXT_PUBLIC_SUPABASE_URL": "",
+ "NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "name": "social-auth-react",
+ "type": "registry:block",
+ "title": "Social Auth flow for React and Supabase",
+ "description": "Social Auth flow for React and Supabase",
+ "registryDependencies": [
+ "button",
+ "card"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/social-auth-react/components/login-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/clients/react/lib/supabase/client.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "dependencies": [
+ "@supabase/supabase-js@latest"
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "name": "social-auth-react-router",
+ "type": "registry:block",
+ "title": "Social Auth flow for React Router and Supabase",
+ "description": "Social Auth flow for React Router and Supabase",
+ "registryDependencies": [
+ "button",
+ "card"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@react-router/dev@latest",
+ "@react-router/fs-routes@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/social-auth-react-router/app/routes/auth.error.tsx",
+ "type": "registry:file",
+ "target": "app/routes/auth.error.tsx"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-react-router/app/routes/auth.oauth.tsx",
+ "type": "registry:file",
+ "target": "app/routes/auth.oauth.tsx"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-react-router/app/routes/login.tsx",
+ "type": "registry:file",
+ "target": "app/routes/login.tsx"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-react-router/app/routes/logout.tsx",
+ "type": "registry:file",
+ "target": "app/routes/logout.tsx"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-react-router/app/routes/protected.tsx",
+ "type": "registry:file",
+ "target": "app/routes/protected.tsx"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-react-router/app/routes.ts",
+ "type": "registry:file",
+ "target": "app/routes.ts"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "name": "social-auth-tanstack",
+ "type": "registry:block",
+ "title": "Social Auth flow for TanStack and Supabase",
+ "description": "Social Auth flow for TanStack and Supabase",
+ "registryDependencies": [
+ "button",
+ "card"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/social-auth-tanstack/components/login-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-tanstack/lib/supabase/fetch-user-server-fn.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-tanstack/routes/_protected.tsx",
+ "type": "registry:file",
+ "target": "routes/_protected.tsx"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-tanstack/routes/_protected/protected.tsx",
+ "type": "registry:file",
+ "target": "routes/_protected/protected.tsx"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-tanstack/routes/auth/error.tsx",
+ "type": "registry:file",
+ "target": "routes/auth/error.tsx"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-tanstack/routes/auth/oauth.ts",
+ "type": "registry:file",
+ "target": "routes/auth/oauth.ts"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-tanstack/routes/login.tsx",
+ "type": "registry:file",
+ "target": "routes/login.tsx"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "dropzone-nextjs",
+ "type": "registry:component",
+ "title": "Dropzone (File Upload)",
+ "description": "Displays a control for easier uploading of files directly to Supabase Storage.",
+ "registryDependencies": [
+ "button"
+ ],
+ "dependencies": [
+ "react-dropzone",
+ "lucide-react",
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/dropzone/components/dropzone.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/dropzone/hooks/use-supabase-upload.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/middleware.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "NEXT_PUBLIC_SUPABASE_URL": "",
+ "NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "dropzone-react",
+ "type": "registry:component",
+ "title": "Dropzone (File Upload)",
+ "description": "Displays a control for easier uploading of files directly to Supabase Storage.",
+ "registryDependencies": [
+ "button"
+ ],
+ "dependencies": [
+ "react-dropzone",
+ "lucide-react",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/dropzone/components/dropzone.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/dropzone/hooks/use-supabase-upload.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/react/lib/supabase/client.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "dropzone-react-router",
+ "type": "registry:component",
+ "title": "Dropzone (File Upload)",
+ "description": "Displays a control for easier uploading of files directly to Supabase Storage.",
+ "registryDependencies": [
+ "button"
+ ],
+ "dependencies": [
+ "react-dropzone",
+ "lucide-react",
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/dropzone/components/dropzone.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/dropzone/hooks/use-supabase-upload.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "dropzone-tanstack",
+ "type": "registry:component",
+ "title": "Dropzone (File Upload)",
+ "description": "Displays a control for easier uploading of files directly to Supabase Storage.",
+ "registryDependencies": [
+ "button"
+ ],
+ "dependencies": [
+ "react-dropzone",
+ "lucide-react",
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/dropzone/components/dropzone.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/dropzone/hooks/use-supabase-upload.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "realtime-cursor-nextjs",
+ "type": "registry:component",
+ "title": "Realtime Cursor",
+ "description": "Component which renders realtime cursors from other users in a room.",
+ "registryDependencies": [],
+ "dependencies": [
+ "lucide-react",
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/realtime-cursor/components/cursor.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-cursor/components/realtime-cursors.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-cursor/hooks/use-realtime-cursors.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/middleware.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "NEXT_PUBLIC_SUPABASE_URL": "",
+ "NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "realtime-cursor-react",
+ "type": "registry:component",
+ "title": "Realtime Cursor",
+ "description": "Component which renders realtime cursors from other users in a room.",
+ "registryDependencies": [],
+ "dependencies": [
+ "lucide-react",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/realtime-cursor/components/cursor.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-cursor/components/realtime-cursors.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-cursor/hooks/use-realtime-cursors.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/react/lib/supabase/client.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "realtime-cursor-react-router",
+ "type": "registry:component",
+ "title": "Realtime Cursor",
+ "description": "Component which renders realtime cursors from other users in a room.",
+ "registryDependencies": [],
+ "dependencies": [
+ "lucide-react",
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/realtime-cursor/components/cursor.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-cursor/components/realtime-cursors.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-cursor/hooks/use-realtime-cursors.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "realtime-cursor-tanstack",
+ "type": "registry:component",
+ "title": "Realtime Cursor",
+ "description": "Component which renders realtime cursors from other users in a room.",
+ "registryDependencies": [],
+ "dependencies": [
+ "lucide-react",
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/realtime-cursor/components/cursor.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-cursor/components/realtime-cursors.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-cursor/hooks/use-realtime-cursors.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "current-user-avatar-nextjs",
+ "type": "registry:component",
+ "title": "Current User Avatar",
+ "description": "Component which renders the current user's avatar.",
+ "registryDependencies": [
+ "avatar"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/current-user-avatar/components/current-user-avatar.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-name.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-image.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/middleware.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "NEXT_PUBLIC_SUPABASE_URL": "",
+ "NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "current-user-avatar-react",
+ "type": "registry:component",
+ "title": "Current User Avatar",
+ "description": "Component which renders the current user's avatar.",
+ "registryDependencies": [
+ "avatar"
+ ],
+ "dependencies": [
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/current-user-avatar/components/current-user-avatar.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-name.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-image.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/react/lib/supabase/client.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "current-user-avatar-react-router",
+ "type": "registry:component",
+ "title": "Current User Avatar",
+ "description": "Component which renders the current user's avatar.",
+ "registryDependencies": [
+ "avatar"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/current-user-avatar/components/current-user-avatar.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-name.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-image.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "current-user-avatar-tanstack",
+ "type": "registry:component",
+ "title": "Current User Avatar",
+ "description": "Component which renders the current user's avatar.",
+ "registryDependencies": [
+ "avatar"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/current-user-avatar/components/current-user-avatar.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-name.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-image.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "realtime-avatar-stack-nextjs",
+ "type": "registry:component",
+ "title": "Avatar Stack with Realtime Presence",
+ "description": "Component which stack of avatars, tracked by realtime presence.",
+ "registryDependencies": [
+ "avatar",
+ "tooltip"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/realtime-avatar-stack/components/avatar-stack.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-avatar-stack/components/realtime-avatar-stack.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-avatar-stack/hooks/use-realtime-presence-room.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-name.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-image.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/middleware.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "NEXT_PUBLIC_SUPABASE_URL": "",
+ "NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "realtime-avatar-stack-react",
+ "type": "registry:component",
+ "title": "Avatar Stack with Realtime Presence",
+ "description": "Component which stack of avatars, tracked by realtime presence.",
+ "registryDependencies": [
+ "avatar",
+ "tooltip"
+ ],
+ "dependencies": [
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/realtime-avatar-stack/components/avatar-stack.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-avatar-stack/components/realtime-avatar-stack.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-avatar-stack/hooks/use-realtime-presence-room.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-name.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-image.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/react/lib/supabase/client.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "realtime-avatar-stack-react-router",
+ "type": "registry:component",
+ "title": "Avatar Stack with Realtime Presence",
+ "description": "Component which stack of avatars, tracked by realtime presence.",
+ "registryDependencies": [
+ "avatar",
+ "tooltip"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/realtime-avatar-stack/components/avatar-stack.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-avatar-stack/components/realtime-avatar-stack.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-avatar-stack/hooks/use-realtime-presence-room.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-name.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-image.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "realtime-avatar-stack-tanstack",
+ "type": "registry:component",
+ "title": "Avatar Stack with Realtime Presence",
+ "description": "Component which stack of avatars, tracked by realtime presence.",
+ "registryDependencies": [
+ "avatar",
+ "tooltip"
+ ],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/realtime-avatar-stack/components/avatar-stack.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-avatar-stack/components/realtime-avatar-stack.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-avatar-stack/hooks/use-realtime-presence-room.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-name.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/current-user-avatar/hooks/use-current-user-image.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "realtime-chat-nextjs",
+ "type": "registry:component",
+ "title": "Realtime Chat",
+ "description": "Component which renders realtime chat messages from other users in a room.",
+ "registryDependencies": [
+ "input",
+ "button"
+ ],
+ "dependencies": [
+ "lucide-react",
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/realtime-chat/components/chat-message.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-chat/components/realtime-chat.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-chat/hooks/use-realtime-chat.tsx",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/realtime-chat/hooks/use-chat-scroll.tsx",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/middleware.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "NEXT_PUBLIC_SUPABASE_URL": "",
+ "NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "realtime-chat-react",
+ "type": "registry:component",
+ "title": "Realtime Chat",
+ "description": "Component which renders realtime chat messages from other users in a room.",
+ "registryDependencies": [
+ "input",
+ "button"
+ ],
+ "dependencies": [
+ "lucide-react",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/realtime-chat/components/chat-message.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-chat/components/realtime-chat.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-chat/hooks/use-realtime-chat.tsx",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/realtime-chat/hooks/use-chat-scroll.tsx",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/react/lib/supabase/client.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "realtime-chat-react-router",
+ "type": "registry:component",
+ "title": "Realtime Chat",
+ "description": "Component which renders realtime chat messages from other users in a room.",
+ "registryDependencies": [
+ "input",
+ "button"
+ ],
+ "dependencies": [
+ "lucide-react",
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/realtime-chat/components/chat-message.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-chat/components/realtime-chat.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-chat/hooks/use-realtime-chat.tsx",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/realtime-chat/hooks/use-chat-scroll.tsx",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "realtime-chat-tanstack",
+ "type": "registry:component",
+ "title": "Realtime Chat",
+ "description": "Component which renders realtime chat messages from other users in a room.",
+ "registryDependencies": [
+ "input",
+ "button"
+ ],
+ "dependencies": [
+ "lucide-react",
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "files": [
+ {
+ "path": "registry/default/blocks/realtime-chat/components/chat-message.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-chat/components/realtime-chat.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/realtime-chat/hooks/use-realtime-chat.tsx",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/blocks/realtime-chat/hooks/use-chat-scroll.tsx",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "infinite-query-hook",
+ "type": "registry:block",
+ "title": "Infinite Query Hook",
+ "description": "React hook for infinite lists, fetching data from Supabase.",
+ "dependencies": [
+ "@supabase/supabase-js",
+ "@supabase/postgrest-js@*"
+ ],
+ "registryDependencies": [],
+ "files": [
+ {
+ "path": "registry/default/blocks/infinite-query-hook/hooks/use-infinite-query.ts",
+ "type": "registry:hook"
+ }
+ ]
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "supabase-client-nextjs",
+ "type": "registry:lib",
+ "title": "Supabase Client for Next.js",
+ "description": "",
+ "registryDependencies": [],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "NEXT_PUBLIC_SUPABASE_URL": "",
+ "NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ },
+ "files": [
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/middleware.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ]
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "supabase-client-react",
+ "type": "registry:lib",
+ "title": "Supabase Client for React",
+ "description": "",
+ "registryDependencies": [],
+ "dependencies": [
+ "@supabase/supabase-js@latest"
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ },
+ "files": [
+ {
+ "path": "registry/default/clients/react/lib/supabase/client.ts",
+ "type": "registry:lib"
+ }
+ ]
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "supabase-client-react-router",
+ "type": "registry:lib",
+ "title": "Supabase Client for React Router",
+ "description": "",
+ "registryDependencies": [],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ },
+ "files": [
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/react-router/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ]
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "supabase-client-tanstack",
+ "type": "registry:lib",
+ "title": "Supabase Client for TanStack Start",
+ "description": "",
+ "registryDependencies": [],
+ "dependencies": [
+ "@supabase/ssr@latest",
+ "@supabase/supabase-js@latest"
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "VITE_SUPABASE_URL": "",
+ "VITE_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ },
+ "files": [
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/tanstack/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ]
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "platform-kit-nextjs",
+ "type": "registry:block",
+ "title": "Platform Kit for Nextjs and Supabase",
+ "description": "Platform Kit for Nextjs and Supabase",
+ "registryDependencies": [
+ "alert",
+ "badge",
+ "button",
+ "card",
+ "chart",
+ "command",
+ "dialog",
+ "drawer",
+ "form",
+ "hover-card",
+ "input",
+ "label",
+ "popover",
+ "select",
+ "skeleton",
+ "switch",
+ "table",
+ "toggle",
+ "toggle-group",
+ "tooltip"
+ ],
+ "dependencies": [
+ "@hookform/resolvers",
+ "@monaco-editor/react",
+ "@tanstack/react-query",
+ "@tanstack/react-table",
+ "axios",
+ "cmdk",
+ "common-tags",
+ "openai",
+ "openapi-fetch",
+ "react-hook-form",
+ "react-markdown",
+ "recharts",
+ "sonner"
+ ],
+ "files": [
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/app/api/ai/sql/route.ts",
+ "type": "registry:page",
+ "target": "app/api/ai/sql/route.ts"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/app/api/supabase-proxy/[...path]/route.ts",
+ "type": "registry:page",
+ "target": "app/api/supabase-proxy/[...path]/route.ts"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/dynamic-form.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/logo-supabase.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/results-table.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/sql-editor.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/supabase-manager/auth.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/supabase-manager/database.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/supabase-manager/index.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/supabase-manager/logs.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/supabase-manager/secrets.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/supabase-manager/storage.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/supabase-manager/suggestions.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/supabase-manager/users.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/components/users-growth-chart.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/hooks/use-auth.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/hooks/use-logs.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/hooks/use-run-query.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/hooks/use-secrets.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/hooks/use-storage.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/hooks/use-suggestions.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/hooks/use-tables.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/hooks/use-user-counts.ts",
+ "type": "registry:hook"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/lib/logs.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/lib/management-api-schema.d.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/lib/management-api.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/lib/pg-meta/sql.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/lib/pg-meta/index.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/lib/pg-meta/types.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/lib/schemas/auth.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/lib/schemas/secrets.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/platform/platform-kit-nextjs/contexts/SheetNavigationContext.tsx",
+ "type": "registry:component",
+ "target": "contexts/SheetNavigationContext.tsx"
+ }
+ ]
+ },
+ {
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "ai-editor-rules",
+ "type": "registry:file",
+ "title": "Prompt rules for AI Editors",
+ "description": "Prompts for working with Supabase using AI-powered IDE tools",
+ "registryDependencies": [],
+ "dependencies": [],
+ "files": [
+ {
+ "path": "registry/default/ai-editor-rules/create-db-functions.mdc",
+ "type": "registry:file",
+ "target": "~/.cursor/rules/create-db-functions.mdc"
+ },
+ {
+ "path": "registry/default/ai-editor-rules/create-migration.mdc",
+ "type": "registry:file",
+ "target": "~/.cursor/rules/create-migration.mdc"
+ },
+ {
+ "path": "registry/default/ai-editor-rules/create-rls-policies.mdc",
+ "type": "registry:file",
+ "target": "~/.cursor/rules/create-rls-policies.mdc"
+ },
+ {
+ "path": "registry/default/ai-editor-rules/postgres-sql-style-guide.mdc",
+ "type": "registry:file",
+ "target": "~/.cursor/rules/postgres-sql-style-guide.mdc"
+ },
+ {
+ "path": "registry/default/ai-editor-rules/writing-supabase-edge-functions.mdc",
+ "type": "registry:file",
+ "target": "~/.cursor/rules/writing-supabase-edge-functions.mdc"
+ },
+ {
+ "path": "registry/default/ai-editor-rules/use-realtime.mdc",
+ "type": "registry:file",
+ "target": "~/.cursor/rules/use-realtime.mdc"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apps/ui-library/public/r/social-auth-nextjs.json b/apps/ui-library/public/r/social-auth-nextjs.json
index df08867c11c..4c06500fa9c 100644
--- a/apps/ui-library/public/r/social-auth-nextjs.json
+++ b/apps/ui-library/public/r/social-auth-nextjs.json
@@ -13,12 +13,6 @@
"card"
],
"files": [
- {
- "path": "registry/default/blocks/social-auth-nextjs/app/auth/login/page.tsx",
- "content": "import { LoginForm } from '@/registry/default/blocks/social-auth-nextjs/components/login-form'\n\nexport default function Page() {\n return (\n \n )\n}\n",
- "type": "registry:page",
- "target": "app/auth/login/page.tsx"
- },
{
"path": "registry/default/blocks/social-auth-nextjs/app/auth/error/page.tsx",
"content": "import { Card, CardContent, CardHeader, CardTitle } from '@/registry/default/components/ui/card'\n\nexport default async function Page({ searchParams }: { searchParams: Promise<{ error: string }> }) {\n const params = await searchParams\n\n return (\n \n
\n
\n
\n \n Sorry, something went wrong. \n \n \n {params?.error ? (\n Code error: {params.error}
\n ) : (\n An unspecified error occurred.
\n )}\n \n \n
\n
\n
\n )\n}\n",
@@ -37,11 +31,6 @@
"type": "registry:page",
"target": "app/auth/oauth/route.ts"
},
- {
- "path": "registry/default/blocks/social-auth-nextjs/components/login-form.tsx",
- "content": "'use client'\n\nimport { cn } from '@/lib/utils'\nimport { createClient } from '@/registry/default/clients/nextjs/lib/supabase/client'\nimport { Button } from '@/registry/default/components/ui/button'\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n} from '@/registry/default/components/ui/card'\nimport { useState } from 'react'\n\nexport function LoginForm({ className, ...props }: React.ComponentPropsWithoutRef<'div'>) {\n const [error, setError] = useState(null)\n const [isLoading, setIsLoading] = useState(false)\n\n const handleSocialLogin = async (e: React.FormEvent) => {\n e.preventDefault()\n const supabase = createClient()\n setIsLoading(true)\n setError(null)\n\n try {\n const { error } = await supabase.auth.signInWithOAuth({\n provider: 'github',\n options: {\n redirectTo: `${window.location.origin}/auth/oauth?next=/protected`,\n },\n })\n\n if (error) throw error\n } catch (error: unknown) {\n setError(error instanceof Error ? error.message : 'An error occurred')\n setIsLoading(false)\n }\n }\n\n return (\n \n
\n \n Welcome! \n Sign in to your account to continue \n \n \n \n \n \n
\n )\n}\n",
- "type": "registry:component"
- },
{
"path": "registry/default/blocks/social-auth-nextjs/middleware.ts",
"content": "import { updateSession } from '@/registry/default/clients/nextjs/lib/supabase/middleware'\nimport { type NextRequest } from 'next/server'\n\nexport async function middleware(request: NextRequest) {\n return await updateSession(request)\n}\n\nexport const config = {\n matcher: [\n /*\n * Match all request paths except for the ones starting with:\n * - _next/static (static files)\n * - _next/image (image optimization files)\n * - favicon.ico (favicon file)\n * Feel free to modify this pattern to include more paths.\n */\n '/((?!_next/static|_next/image|favicon.ico|.*\\\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',\n ],\n}\n",
@@ -53,6 +42,11 @@
"content": "'use client'\n\nimport { createClient } from '@/registry/default/clients/nextjs/lib/supabase/client'\nimport { Button } from '@/registry/default/components/ui/button'\nimport { useRouter } from 'next/navigation'\n\nexport function LogoutButton() {\n const router = useRouter()\n\n const logout = async () => {\n const supabase = createClient()\n await supabase.auth.signOut()\n router.push('/auth/login')\n }\n\n return Logout \n}\n",
"type": "registry:component"
},
+ {
+ "path": "registry/default/blocks/social-auth-nextjs/components/social-login-button.tsx",
+ "content": "'use client'\n\nimport { createClient } from '@/registry/default/clients/nextjs/lib/supabase/client'\nimport { Button } from '@/registry/default/components/ui/button'\nimport { type Provider } from '@supabase/supabase-js'\nimport { useState } from 'react'\n\nexport function SocialLoginButton({ label, provider }: { label: string; provider: Provider }) {\n const [error, setError] = useState(null)\n const [isLoading, setIsLoading] = useState(false)\n\n const handleSocialLogin = async (e: React.FormEvent) => {\n e.preventDefault()\n const supabase = createClient()\n setIsLoading(true)\n setError(null)\n\n try {\n const { error } = await supabase.auth.signInWithOAuth({\n provider,\n options: {\n redirectTo: `${window.location.origin}/auth/oauth?next=/protected`,\n },\n })\n\n if (error) throw error\n } catch (error: unknown) {\n setError(error instanceof Error ? error.message : 'An error occurred')\n setIsLoading(false)\n }\n }\n\n return (\n \n )\n}\n",
+ "type": "registry:component"
+ },
{
"path": "registry/default/clients/nextjs/lib/supabase/client.ts",
"content": "import { createBrowserClient } from '@supabase/ssr'\n\nexport function createClient() {\n return createBrowserClient(\n process.env.NEXT_PUBLIC_SUPABASE_URL!,\n process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY!\n )\n}\n",
diff --git a/apps/ui-library/registry.json b/apps/ui-library/registry.json
index 5b9ff396fe1..d014887933f 100644
--- a/apps/ui-library/registry.json
+++ b/apps/ui-library/registry.json
@@ -3,6 +3,57 @@
"name": "Supabase UI Library",
"homepage": "https://supabase.com/ui",
"items": [
+ {
+ "name": "common-auth-nextjs",
+ "type": "registry:block",
+ "title": "Common Auth flow for Nextjs and Supabase",
+ "description": "Common Auth flow for Nextjs and Supabase",
+ "registryDependencies": ["button", "card", "input", "label"],
+ "dependencies": ["@supabase/ssr@latest", "@supabase/supabase-js@latest"],
+ "files": [
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/app/auth/login/page.tsx",
+ "type": "registry:page",
+ "target": "app/auth/login/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/app/auth/error/page.tsx",
+ "type": "registry:page",
+ "target": "app/auth/error/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/app/protected/page.tsx",
+ "type": "registry:page",
+ "target": "app/protected/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/middleware.ts",
+ "type": "registry:file",
+ "target": "middleware.ts"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/components/logout-button.tsx",
+ "type": "registry:component"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/client.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/middleware.ts",
+ "type": "registry:lib"
+ },
+ {
+ "path": "registry/default/clients/nextjs/lib/supabase/server.ts",
+ "type": "registry:lib"
+ }
+ ],
+ "docs": "You'll need to set the following environment variables in your project: `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY`.",
+ "envVars": {
+ "NEXT_PUBLIC_SUPABASE_URL": "",
+ "NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY": ""
+ }
+ },
{
"name": "password-based-auth-nextjs",
"type": "registry:block",
@@ -11,11 +62,6 @@
"registryDependencies": ["button", "card", "input", "label"],
"dependencies": ["@supabase/ssr@latest", "@supabase/supabase-js@latest"],
"files": [
- {
- "path": "registry/default/blocks/password-based-auth-nextjs/app/auth/login/page.tsx",
- "type": "registry:page",
- "target": "app/auth/login/page.tsx"
- },
{
"path": "registry/default/blocks/password-based-auth-nextjs/app/auth/error/page.tsx",
"type": "registry:page",
@@ -31,10 +77,6 @@
"type": "registry:page",
"target": "app/auth/confirm/route.ts"
},
- {
- "path": "registry/default/blocks/password-based-auth-nextjs/components/login-form.tsx",
- "type": "registry:component"
- },
{
"path": "registry/default/blocks/password-based-auth-nextjs/middleware.ts",
"type": "registry:file",
@@ -76,6 +118,10 @@
"path": "registry/default/blocks/password-based-auth-nextjs/components/logout-button.tsx",
"type": "registry:component"
},
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/components/password-login-form.tsx",
+ "type": "registry:component"
+ },
{
"path": "registry/default/clients/nextjs/lib/supabase/client.ts",
"type": "registry:lib"
@@ -299,11 +345,6 @@
"registryDependencies": ["button", "card"],
"dependencies": ["@supabase/ssr@latest", "@supabase/supabase-js@latest"],
"files": [
- {
- "path": "registry/default/blocks/social-auth-nextjs/app/auth/login/page.tsx",
- "type": "registry:page",
- "target": "app/auth/login/page.tsx"
- },
{
"path": "registry/default/blocks/social-auth-nextjs/app/auth/error/page.tsx",
"type": "registry:page",
@@ -319,10 +360,6 @@
"type": "registry:page",
"target": "app/auth/oauth/route.ts"
},
- {
- "path": "registry/default/blocks/social-auth-nextjs/components/login-form.tsx",
- "type": "registry:component"
- },
{
"path": "registry/default/blocks/social-auth-nextjs/middleware.ts",
"type": "registry:file",
@@ -332,6 +369,10 @@
"path": "registry/default/blocks/social-auth-nextjs/components/logout-button.tsx",
"type": "registry:component"
},
+ {
+ "path": "registry/default/blocks/social-auth-nextjs/components/social-login-button.tsx",
+ "type": "registry:component"
+ },
{
"path": "registry/default/clients/nextjs/lib/supabase/client.ts",
"type": "registry:lib"
diff --git a/apps/ui-library/registry/blocks.ts b/apps/ui-library/registry/blocks.ts
index 53183786f00..273a385e70a 100644
--- a/apps/ui-library/registry/blocks.ts
+++ b/apps/ui-library/registry/blocks.ts
@@ -9,6 +9,7 @@ import realtimeAvatarStack from './default/blocks/realtime-avatar-stack/registry
import realtimeChat from './default/blocks/realtime-chat/registry-item.json' with { type: 'json' }
import realtimeCursor from './default/blocks/realtime-cursor/registry-item.json' with { type: 'json' }
+import commonAuthNextjs from './default/blocks/common-auth-nextjs/registry-item.json' with { type: 'json' }
import passwordBasedAuthNextjs from './default/blocks/password-based-auth-nextjs/registry-item.json' with { type: 'json' }
import passwordBasedAuthReactRouter from './default/blocks/password-based-auth-react-router/registry-item.json' with { type: 'json' }
import passwordBasedAuthReact from './default/blocks/password-based-auth-react/registry-item.json' with { type: 'json' }
@@ -19,7 +20,7 @@ import socialAuthReactRouter from './default/blocks/social-auth-react-router/reg
import socialAuthReact from './default/blocks/social-auth-react/registry-item.json' with { type: 'json' }
import socialAuthTanstack from './default/blocks/social-auth-tanstack/registry-item.json' with { type: 'json' }
-const combine = (component: Registry['items'][number]) => {
+const combine = (component: RegistryItem) => {
return clients.flatMap((client) => {
return registryItemAppend(
{
@@ -37,6 +38,8 @@ const tanstackClient = clients.find((client) => client.name === 'supabase-client
const reactRouterClient = clients.find((client) => client.name === 'supabase-client-react-router')
export const blocks = [
+ registryItemAppend(commonAuthNextjs as RegistryItem, [nextjsClient!]),
+
registryItemAppend(passwordBasedAuthNextjs as RegistryItem, [nextjsClient!]),
registryItemAppend(passwordBasedAuthReact as RegistryItem, [reactClient!]),
registryItemAppend(passwordBasedAuthReactRouter as RegistryItem, [reactRouterClient!]),
@@ -54,4 +57,4 @@ export const blocks = [
...combine(realtimeChat as RegistryItem),
// infinite query hook is intentionally not combined with the clients since it depends on clients having database types.
infiniteQueryHook as RegistryItem,
-] as Registry['items']
+] as RegistryItem[]
diff --git a/apps/ui-library/registry/default/blocks/common-auth-nextjs/app/auth/error/page.tsx b/apps/ui-library/registry/default/blocks/common-auth-nextjs/app/auth/error/page.tsx
new file mode 100644
index 00000000000..ed8def8595f
--- /dev/null
+++ b/apps/ui-library/registry/default/blocks/common-auth-nextjs/app/auth/error/page.tsx
@@ -0,0 +1,26 @@
+import { Card, CardContent, CardHeader, CardTitle } from '@/registry/default/components/ui/card'
+
+export default async function Page({ searchParams }: { searchParams: Promise<{ error: string }> }) {
+ const params = await searchParams
+
+ return (
+
+
+
+
+
+ Sorry, something went wrong.
+
+
+ {params?.error ? (
+ Code error: {params.error}
+ ) : (
+ An unspecified error occurred.
+ )}
+
+
+
+
+
+ )
+}
diff --git a/apps/ui-library/registry/default/blocks/common-auth-nextjs/app/auth/login/page.tsx b/apps/ui-library/registry/default/blocks/common-auth-nextjs/app/auth/login/page.tsx
new file mode 100644
index 00000000000..b476dac8ea8
--- /dev/null
+++ b/apps/ui-library/registry/default/blocks/common-auth-nextjs/app/auth/login/page.tsx
@@ -0,0 +1,26 @@
+import {
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from '@/registry/default/components/ui/card'
+/*<%= imports %> */
+
+export default function Page() {
+ return (
+
+
+
+
+
+ Login
+ Sign in to your account to continue
+
+ {/*<%= components %> */}
+
+
+
+
+ )
+}
diff --git a/apps/ui-library/registry/default/blocks/common-auth-nextjs/app/protected/page.tsx b/apps/ui-library/registry/default/blocks/common-auth-nextjs/app/protected/page.tsx
new file mode 100644
index 00000000000..f84213f2771
--- /dev/null
+++ b/apps/ui-library/registry/default/blocks/common-auth-nextjs/app/protected/page.tsx
@@ -0,0 +1,22 @@
+import { redirect } from 'next/navigation'
+
+import { LogoutButton } from '@/registry/default/blocks/password-based-auth-nextjs/components/logout-button'
+import { createClient } from '@/registry/default/clients/nextjs/lib/supabase/server'
+
+export default async function ProtectedPage() {
+ const supabase = await createClient()
+
+ const { data, error } = await supabase.auth.getClaims()
+ if (error || !data?.claims) {
+ redirect('/auth/login')
+ }
+
+ return (
+
+
+ Hello {data.claims.email}
+
+
+
+ )
+}
diff --git a/apps/ui-library/registry/default/blocks/common-auth-nextjs/components/logout-button.tsx b/apps/ui-library/registry/default/blocks/common-auth-nextjs/components/logout-button.tsx
new file mode 100644
index 00000000000..88110ddc6c7
--- /dev/null
+++ b/apps/ui-library/registry/default/blocks/common-auth-nextjs/components/logout-button.tsx
@@ -0,0 +1,17 @@
+'use client'
+
+import { createClient } from '@/registry/default/clients/nextjs/lib/supabase/client'
+import { Button } from '@/registry/default/components/ui/button'
+import { useRouter } from 'next/navigation'
+
+export function LogoutButton() {
+ const router = useRouter()
+
+ const logout = async () => {
+ const supabase = createClient()
+ await supabase.auth.signOut()
+ router.push('/example/password-based-auth/auth/login')
+ }
+
+ return Logout
+}
diff --git a/apps/ui-library/registry/default/blocks/common-auth-nextjs/middleware.ts b/apps/ui-library/registry/default/blocks/common-auth-nextjs/middleware.ts
new file mode 100644
index 00000000000..c04d54bc883
--- /dev/null
+++ b/apps/ui-library/registry/default/blocks/common-auth-nextjs/middleware.ts
@@ -0,0 +1,19 @@
+import { updateSession } from '@/registry/default/clients/nextjs/lib/supabase/middleware'
+import { type NextRequest } from 'next/server'
+
+export async function middleware(request: NextRequest) {
+ return await updateSession(request)
+}
+
+export const config = {
+ matcher: [
+ /*
+ * Match all request paths except for the ones starting with:
+ * - _next/static (static files)
+ * - _next/image (image optimization files)
+ * - favicon.ico (favicon file)
+ * Feel free to modify this pattern to include more paths.
+ */
+ '/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
+ ],
+}
diff --git a/apps/ui-library/registry/default/blocks/common-auth-nextjs/registry-item.json b/apps/ui-library/registry/default/blocks/common-auth-nextjs/registry-item.json
new file mode 100644
index 00000000000..c80776274f9
--- /dev/null
+++ b/apps/ui-library/registry/default/blocks/common-auth-nextjs/registry-item.json
@@ -0,0 +1,34 @@
+{
+ "name": "common-auth-nextjs",
+ "type": "registry:block",
+ "title": "Common Auth flow for Nextjs and Supabase",
+ "description": "Common Auth flow for Nextjs and Supabase",
+ "registryDependencies": ["button", "card", "input", "label"],
+ "dependencies": ["@supabase/ssr@latest", "@supabase/supabase-js@latest"],
+ "files": [
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/app/auth/login/page.tsx",
+ "type": "registry:page",
+ "target": "app/auth/login/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/app/auth/error/page.tsx",
+ "type": "registry:page",
+ "target": "app/auth/error/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/app/protected/page.tsx",
+ "type": "registry:page",
+ "target": "app/protected/page.tsx"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/middleware.ts",
+ "type": "registry:file",
+ "target": "middleware.ts"
+ },
+ {
+ "path": "registry/default/blocks/common-auth-nextjs/components/logout-button.tsx",
+ "type": "registry:component"
+ }
+ ]
+}
diff --git a/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/app/auth/login/page.tsx b/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/app/auth/login/page.tsx
index 0cd66abb285..5a7fb44c390 100644
--- a/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/app/auth/login/page.tsx
+++ b/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/app/auth/login/page.tsx
@@ -1,10 +1,10 @@
-import { LoginForm } from '@/registry/default/blocks/password-based-auth-nextjs/components/login-form'
+import { PasswordLoginForm } from '@/registry/default/blocks/password-based-auth-nextjs/components/password-login-form'
export default function Page() {
return (
)
diff --git a/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/components/login-form.tsx b/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/components/login-form.tsx
deleted file mode 100644
index 6a4d2231d89..00000000000
--- a/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/components/login-form.tsx
+++ /dev/null
@@ -1,102 +0,0 @@
-'use client'
-
-import { cn } from '@/lib/utils'
-import { createClient } from '@/registry/default/clients/nextjs/lib/supabase/client'
-import { Button } from '@/registry/default/components/ui/button'
-import {
- Card,
- CardContent,
- CardDescription,
- CardHeader,
- CardTitle,
-} from '@/registry/default/components/ui/card'
-import { Input } from '@/registry/default/components/ui/input'
-import { Label } from '@/registry/default/components/ui/label'
-import { Link } from '@/registry/default/components/ui/link'
-import { useRouter } from 'next/navigation'
-import { useState } from 'react'
-
-export function LoginForm({ className, ...props }: React.ComponentPropsWithoutRef<'div'>) {
- const [email, setEmail] = useState('')
- const [password, setPassword] = useState('')
- const [error, setError] = useState(null)
- const [isLoading, setIsLoading] = useState(false)
- const router = useRouter()
-
- const handleLogin = async (e: React.FormEvent) => {
- e.preventDefault()
- const supabase = createClient()
- setIsLoading(true)
- setError(null)
-
- try {
- const { error } = await supabase.auth.signInWithPassword({
- email,
- password,
- })
- if (error) throw error
- // Update this route to redirect to an authenticated route. The user already has an active session.
- router.push('/example/password-based-auth/protected')
- } catch (error: unknown) {
- setError(error instanceof Error ? error.message : 'An error occurred')
- } finally {
- setIsLoading(false)
- }
- }
-
- return (
-
-
-
- Login
- Enter your email below to login to your account
-
-
-
-
-
-
- )
-}
diff --git a/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/components/password-login-form.tsx b/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/components/password-login-form.tsx
new file mode 100644
index 00000000000..e6f12c3cc7b
--- /dev/null
+++ b/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/components/password-login-form.tsx
@@ -0,0 +1,84 @@
+'use client'
+
+import { createClient } from '@/registry/default/clients/nextjs/lib/supabase/client'
+import { Button } from '@/registry/default/components/ui/button'
+import { Input } from '@/registry/default/components/ui/input'
+import { Label } from '@/registry/default/components/ui/label'
+import { Link } from '@/registry/default/components/ui/link'
+import { useRouter } from 'next/navigation'
+import { useState } from 'react'
+
+export function PasswordLoginForm() {
+ const [email, setEmail] = useState('')
+ const [password, setPassword] = useState('')
+ const [error, setError] = useState(null)
+ const [isLoading, setIsLoading] = useState(false)
+ const router = useRouter()
+
+ const handleLogin = async (e: React.FormEvent) => {
+ e.preventDefault()
+ const supabase = createClient()
+ setIsLoading(true)
+ setError(null)
+
+ try {
+ const { error } = await supabase.auth.signInWithPassword({
+ email,
+ password,
+ })
+ if (error) throw error
+ // Update this route to redirect to an authenticated route. The user already has an active session.
+ router.push('/example/password-based-auth/protected')
+ } catch (error: unknown) {
+ setError(error instanceof Error ? error.message : 'An error occurred')
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ return (
+
+ )
+}
diff --git a/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/middleware.ts b/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/middleware.ts
index 71fac6460bd..c04d54bc883 100644
--- a/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/middleware.ts
+++ b/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/middleware.ts
@@ -8,11 +8,10 @@ export async function middleware(request: NextRequest) {
export const config = {
matcher: [
/*
- * Match all request paths except:
+ * Match all request paths except for the ones starting with:
* - _next/static (static files)
* - _next/image (image optimization files)
* - favicon.ico (favicon file)
- * - images - .svg, .png, .jpg, .jpeg, .gif, .webp
* Feel free to modify this pattern to include more paths.
*/
'/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)',
diff --git a/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/registry-item.json b/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/registry-item.json
index 2203774c8dc..fab59e5e599 100644
--- a/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/registry-item.json
+++ b/apps/ui-library/registry/default/blocks/password-based-auth-nextjs/registry-item.json
@@ -6,11 +6,6 @@
"registryDependencies": ["button", "card", "input", "label"],
"dependencies": ["@supabase/ssr@latest", "@supabase/supabase-js@latest"],
"files": [
- {
- "path": "registry/default/blocks/password-based-auth-nextjs/app/auth/login/page.tsx",
- "type": "registry:page",
- "target": "app/auth/login/page.tsx"
- },
{
"path": "registry/default/blocks/password-based-auth-nextjs/app/auth/error/page.tsx",
"type": "registry:page",
@@ -26,10 +21,6 @@
"type": "registry:page",
"target": "app/auth/confirm/route.ts"
},
- {
- "path": "registry/default/blocks/password-based-auth-nextjs/components/login-form.tsx",
- "type": "registry:component"
- },
{
"path": "registry/default/blocks/password-based-auth-nextjs/middleware.ts",
"type": "registry:file",
@@ -70,6 +61,10 @@
{
"path": "registry/default/blocks/password-based-auth-nextjs/components/logout-button.tsx",
"type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/password-based-auth-nextjs/components/password-login-form.tsx",
+ "type": "registry:component"
}
]
}
diff --git a/apps/ui-library/registry/default/blocks/social-auth-nextjs/components/login-form.tsx b/apps/ui-library/registry/default/blocks/social-auth-nextjs/components/login-form.tsx
index ca6a76de612..6144d4f8c49 100644
--- a/apps/ui-library/registry/default/blocks/social-auth-nextjs/components/login-form.tsx
+++ b/apps/ui-library/registry/default/blocks/social-auth-nextjs/components/login-form.tsx
@@ -1,8 +1,6 @@
'use client'
import { cn } from '@/lib/utils'
-import { createClient } from '@/registry/default/clients/nextjs/lib/supabase/client'
-import { Button } from '@/registry/default/components/ui/button'
import {
Card,
CardContent,
@@ -10,33 +8,9 @@ import {
CardHeader,
CardTitle,
} from '@/registry/default/components/ui/card'
-import { useState } from 'react'
+import { SocialLoginButton } from './social-login-button'
export function LoginForm({ className, ...props }: React.ComponentPropsWithoutRef<'div'>) {
- const [error, setError] = useState(null)
- const [isLoading, setIsLoading] = useState(false)
-
- const handleSocialLogin = async (e: React.FormEvent) => {
- e.preventDefault()
- const supabase = createClient()
- setIsLoading(true)
- setError(null)
-
- try {
- const { error } = await supabase.auth.signInWithOAuth({
- provider: 'github',
- options: {
- redirectTo: `${window.location.origin}/auth/oauth?next=/protected`,
- },
- })
-
- if (error) throw error
- } catch (error: unknown) {
- setError(error instanceof Error ? error.message : 'An error occurred')
- setIsLoading(false)
- }
- }
-
return (
@@ -45,14 +19,7 @@ export function LoginForm({ className, ...props }: React.ComponentPropsWithoutRe
Sign in to your account to continue
-
+
diff --git a/apps/ui-library/registry/default/blocks/social-auth-nextjs/components/social-login-button.tsx b/apps/ui-library/registry/default/blocks/social-auth-nextjs/components/social-login-button.tsx
new file mode 100644
index 00000000000..13da61e0d5c
--- /dev/null
+++ b/apps/ui-library/registry/default/blocks/social-auth-nextjs/components/social-login-button.tsx
@@ -0,0 +1,43 @@
+'use client'
+
+import { createClient } from '@/registry/default/clients/nextjs/lib/supabase/client'
+import { Button } from '@/registry/default/components/ui/button'
+import { type Provider } from '@supabase/supabase-js'
+import { useState } from 'react'
+
+export function SocialLoginButton({ label, provider }: { label: string; provider: Provider }) {
+ const [error, setError] = useState(null)
+ const [isLoading, setIsLoading] = useState(false)
+
+ const handleSocialLogin = async (e: React.FormEvent) => {
+ e.preventDefault()
+ const supabase = createClient()
+ setIsLoading(true)
+ setError(null)
+
+ try {
+ const { error } = await supabase.auth.signInWithOAuth({
+ provider,
+ options: {
+ redirectTo: `${window.location.origin}/auth/oauth?next=/protected`,
+ },
+ })
+
+ if (error) throw error
+ } catch (error: unknown) {
+ setError(error instanceof Error ? error.message : 'An error occurred')
+ setIsLoading(false)
+ }
+ }
+
+ return (
+
+ )
+}
diff --git a/apps/ui-library/registry/default/blocks/social-auth-nextjs/registry-item.json b/apps/ui-library/registry/default/blocks/social-auth-nextjs/registry-item.json
index c37a59023ea..acecb29956d 100644
--- a/apps/ui-library/registry/default/blocks/social-auth-nextjs/registry-item.json
+++ b/apps/ui-library/registry/default/blocks/social-auth-nextjs/registry-item.json
@@ -6,11 +6,6 @@
"registryDependencies": ["button", "card"],
"dependencies": ["@supabase/ssr@latest", "@supabase/supabase-js@latest"],
"files": [
- {
- "path": "registry/default/blocks/social-auth-nextjs/app/auth/login/page.tsx",
- "type": "registry:page",
- "target": "app/auth/login/page.tsx"
- },
{
"path": "registry/default/blocks/social-auth-nextjs/app/auth/error/page.tsx",
"type": "registry:page",
@@ -26,10 +21,6 @@
"type": "registry:page",
"target": "app/auth/oauth/route.ts"
},
- {
- "path": "registry/default/blocks/social-auth-nextjs/components/login-form.tsx",
- "type": "registry:component"
- },
{
"path": "registry/default/blocks/social-auth-nextjs/middleware.ts",
"type": "registry:file",
@@ -38,6 +29,10 @@
{
"path": "registry/default/blocks/social-auth-nextjs/components/logout-button.tsx",
"type": "registry:component"
+ },
+ {
+ "path": "registry/default/blocks/social-auth-nextjs/components/social-login-button.tsx",
+ "type": "registry:component"
}
]
}