Somewhat automate types and stuff.
This commit is contained in:
@ -2,14 +2,14 @@
|
||||
|
||||
import 'server-only';
|
||||
import { encodedRedirect } from '@/utils/utils';
|
||||
import { createClient } from '@/utils/supabase/server';
|
||||
import { createServerClient } from '@/utils/supabase';
|
||||
import { headers } from 'next/headers';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
export const signUp = async (formData: FormData) => {
|
||||
const email = formData.get('email') as string;
|
||||
const password = formData.get('password') as string;
|
||||
const supabase = await createClient();
|
||||
const supabase = await createServerClient();
|
||||
const origin = (await headers()).get('origin');
|
||||
|
||||
if (!email || !password) {
|
||||
@ -47,7 +47,7 @@ export const signUp = async (formData: FormData) => {
|
||||
export const signIn = async (formData: FormData) => {
|
||||
const email = formData.get('email') as string;
|
||||
const password = formData.get('password') as string;
|
||||
const supabase = await createClient();
|
||||
const supabase = await createServerClient();
|
||||
|
||||
const { error } = await supabase.auth.signInWithPassword({
|
||||
email,
|
||||
@ -63,7 +63,7 @@ export const signIn = async (formData: FormData) => {
|
||||
|
||||
export const forgotPassword = async (formData: FormData) => {
|
||||
const email = formData.get('email') as string;
|
||||
const supabase = await createClient();
|
||||
const supabase = await createServerClient();
|
||||
const origin = (await headers()).get('origin');
|
||||
const callbackUrl = formData.get('callbackUrl') as string;
|
||||
|
||||
@ -96,7 +96,7 @@ export const forgotPassword = async (formData: FormData) => {
|
||||
};
|
||||
|
||||
export const resetPassword = async (formData: FormData) => {
|
||||
const supabase = await createClient();
|
||||
const supabase = await createServerClient();
|
||||
const password = formData.get('password') as string;
|
||||
const confirmPassword = formData.get('confirmPassword') as string;
|
||||
|
||||
@ -132,7 +132,7 @@ export const resetPassword = async (formData: FormData) => {
|
||||
};
|
||||
|
||||
export const signOut = async () => {
|
||||
const supabase = await createClient();
|
||||
const supabase = await createServerClient();
|
||||
await supabase.auth.signOut();
|
||||
return redirect('/sign-in');
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
'use server';
|
||||
|
||||
import 'server-only';
|
||||
import { createClient } from '@/utils/supabase/server';
|
||||
import { createServerClient } from '@/utils/supabase';
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { createClient } from '@/utils/supabase/server';
|
||||
import { createServerClient } from '@/utils/supabase';
|
||||
import { NextResponse } from 'next/server';
|
||||
|
||||
export async function GET(request: Request) {
|
||||
@ -11,7 +11,7 @@ export async function GET(request: Request) {
|
||||
const redirectTo = requestUrl.searchParams.get('redirect_to')?.toString();
|
||||
|
||||
if (code) {
|
||||
const supabase = await createClient();
|
||||
const supabase = await createServerClient();
|
||||
await supabase.auth.exchangeCodeForSession(code);
|
||||
}
|
||||
|
||||
|
@ -1,12 +1,12 @@
|
||||
'use server';
|
||||
|
||||
import { FetchDataSteps } from '@/components/tutorial';
|
||||
import { createClient } from '@/utils/supabase/server';
|
||||
import { createServerClient } from '@/utils/supabase';
|
||||
import { InfoIcon } from 'lucide-react';
|
||||
import { redirect } from 'next/navigation';
|
||||
|
||||
const ProtectedPage = async () => {
|
||||
const supabase = await createClient();
|
||||
const supabase = await createServerClient();
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
|
@ -1,10 +1,10 @@
|
||||
'use server';
|
||||
|
||||
import { createClient } from '@/utils/supabase/server';
|
||||
import { createServerClient } from '@/utils/supabase';
|
||||
import Image from 'next/image';
|
||||
|
||||
export default async function Page() {
|
||||
const supabase = await createClient();
|
||||
const supabase = await createServerClient();
|
||||
|
||||
// Get authenticated user
|
||||
const {
|
||||
|
@ -3,7 +3,7 @@ import * as React from 'react';
|
||||
import { ThemeProvider as NextThemesProvider } from 'next-themes';
|
||||
import { Moon, Sun } from 'lucide-react';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Button } from '@/components/ui';
|
||||
|
||||
export const ThemeProvider = ({
|
||||
children,
|
||||
|
@ -2,11 +2,11 @@
|
||||
|
||||
import Link from 'next/link';
|
||||
import { Button } from '@/components/ui';
|
||||
import { createClient } from '@/utils/supabase/server';
|
||||
import { createServerClient } from '@/utils/supabase';
|
||||
import { signOut } from '@/actions/auth';
|
||||
|
||||
const NavigationAuth = async () => {
|
||||
const supabase = await createClient();
|
||||
const supabase = await createServerClient();
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
|
@ -43,7 +43,7 @@ export default function Page() {
|
||||
}
|
||||
`.trim();
|
||||
|
||||
const FetchDataSteps = () => {
|
||||
export const FetchDataSteps = () => {
|
||||
return (
|
||||
<ol className='flex flex-col gap-6'>
|
||||
<TutorialStep title='Create some tables and insert some data'>
|
||||
@ -93,4 +93,3 @@ const FetchDataSteps = () => {
|
||||
</ol>
|
||||
);
|
||||
};
|
||||
export default FetchDataSteps;
|
||||
|
@ -1,5 +1,3 @@
|
||||
import { CodeBlock } from '@/components/tutorial/code-block';
|
||||
import FetchDataSteps from '@/components/tutorial/fetch-data-steps';
|
||||
import { TutorialStep } from '@/components/tutorial/tutorial-step';
|
||||
|
||||
export { CodeBlock, FetchDataSteps, TutorialStep };
|
||||
export { CodeBlock } from '@/components/tutorial/code-block';
|
||||
export { FetchDataSteps } from '@/components/tutorial/fetch-data-steps';
|
||||
export { TutorialStep } from '@/components/tutorial/tutorial-step';
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
|
||||
export { Badge, Button, Checkbox, Input, Label };
|
||||
export { Badge } from '@/components/ui/badge';
|
||||
export { Button } from '@/components/ui/button';
|
||||
export { Checkbox } from '@/components/ui/checkbox';
|
||||
export { Input } from '@/components/ui/input';
|
||||
export { Label } from '@/components/ui/label';
|
||||
|
@ -2,7 +2,7 @@
|
||||
create table profiles (
|
||||
id uuid references auth.users on delete cascade not null primary key,
|
||||
updated_at timestamp with time zone,
|
||||
email text,
|
||||
email text unique,
|
||||
full_name text,
|
||||
avatar_url text,
|
||||
provider text,
|
||||
@ -35,7 +35,7 @@ begin
|
||||
new.id,
|
||||
new.email,
|
||||
new.raw_user_meta_data->>'full_name',
|
||||
new.raw_user_meta_data->>'avatar_url'
|
||||
new.raw_user_meta_data->>'avatar_url',
|
||||
new.raw_user_meta_data->>'provider',
|
||||
now()
|
||||
);
|
||||
@ -58,7 +58,6 @@ create policy "Avatar images are publicly accessible." on storage.objects
|
||||
create policy "Anyone can upload an avatar." on storage.objects
|
||||
for insert with check (bucket_id = 'avatars');
|
||||
|
||||
|
||||
-- -- Create a table for public statuses
|
||||
-- CREATE TABLE statuses (
|
||||
-- id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
|
||||
@ -66,8 +65,7 @@ create policy "Anyone can upload an avatar." on storage.objects
|
||||
-- updated_by_id uuid REFERENCES auth.users ON DELETE SET NULL DEFAULT auth.uid(),
|
||||
-- created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
-- status text NOT NULL,
|
||||
-- CONSTRAINT status_length CHECK (char_length(status) >= 3 AND char_length(status) <= 80),
|
||||
-- CONSTRAINT statuses_user_id_fkey FOREIGN KEY (user_id) REFERENCES profiles(id) ON DELETE CASCADE
|
||||
-- CONSTRAINT status_length CHECK (char_length(status) >= 3 AND char_length(status) <= 80)
|
||||
-- );
|
||||
|
||||
-- -- Set up Row Level Security (RLS)
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { createBrowserClient } from '@supabase/ssr';
|
||||
import type { Database } from '@/utils/supabase/types';
|
||||
|
||||
export const createClient = () =>
|
||||
createBrowserClient(
|
||||
createBrowserClient<Database>(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
);
|
||||
|
5
src/utils/supabase/index.ts
Normal file
5
src/utils/supabase/index.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export { createClient } from './client';
|
||||
export { createClient as createServerClient } from './server';
|
||||
export { updateSession } from './middleware';
|
||||
export type * from './utils';
|
||||
export type { Database } from './types';
|
@ -1,5 +1,6 @@
|
||||
import { createServerClient } from '@supabase/ssr';
|
||||
import { type NextRequest, NextResponse } from 'next/server';
|
||||
import type { Database } from '@/utils/supabase/types';
|
||||
|
||||
export const updateSession = async (request: NextRequest) => {
|
||||
// This `try/catch` block is only here for the interactive tutorial.
|
||||
@ -12,7 +13,7 @@ export const updateSession = async (request: NextRequest) => {
|
||||
},
|
||||
});
|
||||
|
||||
const supabase = createServerClient(
|
||||
const supabase = createServerClient<Database>(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
{
|
||||
|
@ -1,10 +1,11 @@
|
||||
import { createServerClient } from '@supabase/ssr';
|
||||
import type { Database } from '@/utils/supabase/types';
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
export const createClient = async () => {
|
||||
const cookieStore = await cookies();
|
||||
|
||||
return createServerClient(
|
||||
return createServerClient<Database>(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
{
|
||||
|
188
src/utils/supabase/types.ts
Normal file
188
src/utils/supabase/types.ts
Normal file
@ -0,0 +1,188 @@
|
||||
export type Json =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
| { [key: string]: Json | undefined }
|
||||
| Json[];
|
||||
|
||||
export type Database = {
|
||||
public: {
|
||||
Tables: {
|
||||
profiles: {
|
||||
Row: {
|
||||
avatar_url: string | null;
|
||||
email: string | null;
|
||||
full_name: string | null;
|
||||
id: string;
|
||||
provider: string | null;
|
||||
updated_at: string | null;
|
||||
};
|
||||
Insert: {
|
||||
avatar_url?: string | null;
|
||||
email?: string | null;
|
||||
full_name?: string | null;
|
||||
id: string;
|
||||
provider?: string | null;
|
||||
updated_at?: string | null;
|
||||
};
|
||||
Update: {
|
||||
avatar_url?: string | null;
|
||||
email?: string | null;
|
||||
full_name?: string | null;
|
||||
id?: string;
|
||||
provider?: string | null;
|
||||
updated_at?: string | null;
|
||||
};
|
||||
Relationships: [];
|
||||
};
|
||||
statuses: {
|
||||
Row: {
|
||||
created_at: string;
|
||||
id: string;
|
||||
status: string;
|
||||
updated_by_id: string | null;
|
||||
user_id: string;
|
||||
};
|
||||
Insert: {
|
||||
created_at?: string;
|
||||
id?: string;
|
||||
status: string;
|
||||
updated_by_id?: string | null;
|
||||
user_id: string;
|
||||
};
|
||||
Update: {
|
||||
created_at?: string;
|
||||
id?: string;
|
||||
status?: string;
|
||||
updated_by_id?: string | null;
|
||||
user_id?: string;
|
||||
};
|
||||
Relationships: [];
|
||||
};
|
||||
};
|
||||
Views: {
|
||||
[_ in never]: never;
|
||||
};
|
||||
Functions: {
|
||||
[_ in never]: never;
|
||||
};
|
||||
Enums: {
|
||||
[_ in never]: never;
|
||||
};
|
||||
CompositeTypes: {
|
||||
[_ in never]: never;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
type DefaultSchema = Database[Extract<keyof Database, 'public'>];
|
||||
|
||||
export type Tables<
|
||||
DefaultSchemaTableNameOrOptions extends
|
||||
| keyof (DefaultSchema['Tables'] & DefaultSchema['Views'])
|
||||
| { schema: keyof Database },
|
||||
TableName extends DefaultSchemaTableNameOrOptions extends {
|
||||
schema: keyof Database;
|
||||
}
|
||||
? keyof (Database[DefaultSchemaTableNameOrOptions['schema']]['Tables'] &
|
||||
Database[DefaultSchemaTableNameOrOptions['schema']]['Views'])
|
||||
: never = never,
|
||||
> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database }
|
||||
? (Database[DefaultSchemaTableNameOrOptions['schema']]['Tables'] &
|
||||
Database[DefaultSchemaTableNameOrOptions['schema']]['Views'])[TableName] extends {
|
||||
Row: infer R;
|
||||
}
|
||||
? R
|
||||
: never
|
||||
: DefaultSchemaTableNameOrOptions extends keyof (DefaultSchema['Tables'] &
|
||||
DefaultSchema['Views'])
|
||||
? (DefaultSchema['Tables'] &
|
||||
DefaultSchema['Views'])[DefaultSchemaTableNameOrOptions] extends {
|
||||
Row: infer R;
|
||||
}
|
||||
? R
|
||||
: never
|
||||
: never;
|
||||
|
||||
export type TablesInsert<
|
||||
DefaultSchemaTableNameOrOptions extends
|
||||
| keyof DefaultSchema['Tables']
|
||||
| { schema: keyof Database },
|
||||
TableName extends DefaultSchemaTableNameOrOptions extends {
|
||||
schema: keyof Database;
|
||||
}
|
||||
? keyof Database[DefaultSchemaTableNameOrOptions['schema']]['Tables']
|
||||
: never = never,
|
||||
> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database }
|
||||
? Database[DefaultSchemaTableNameOrOptions['schema']]['Tables'][TableName] extends {
|
||||
Insert: infer I;
|
||||
}
|
||||
? I
|
||||
: never
|
||||
: DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables']
|
||||
? DefaultSchema['Tables'][DefaultSchemaTableNameOrOptions] extends {
|
||||
Insert: infer I;
|
||||
}
|
||||
? I
|
||||
: never
|
||||
: never;
|
||||
|
||||
export type TablesUpdate<
|
||||
DefaultSchemaTableNameOrOptions extends
|
||||
| keyof DefaultSchema['Tables']
|
||||
| { schema: keyof Database },
|
||||
TableName extends DefaultSchemaTableNameOrOptions extends {
|
||||
schema: keyof Database;
|
||||
}
|
||||
? keyof Database[DefaultSchemaTableNameOrOptions['schema']]['Tables']
|
||||
: never = never,
|
||||
> = DefaultSchemaTableNameOrOptions extends { schema: keyof Database }
|
||||
? Database[DefaultSchemaTableNameOrOptions['schema']]['Tables'][TableName] extends {
|
||||
Update: infer U;
|
||||
}
|
||||
? U
|
||||
: never
|
||||
: DefaultSchemaTableNameOrOptions extends keyof DefaultSchema['Tables']
|
||||
? DefaultSchema['Tables'][DefaultSchemaTableNameOrOptions] extends {
|
||||
Update: infer U;
|
||||
}
|
||||
? U
|
||||
: never
|
||||
: never;
|
||||
|
||||
export type Enums<
|
||||
DefaultSchemaEnumNameOrOptions extends
|
||||
| keyof DefaultSchema['Enums']
|
||||
| { schema: keyof Database },
|
||||
EnumName extends DefaultSchemaEnumNameOrOptions extends {
|
||||
schema: keyof Database;
|
||||
}
|
||||
? keyof Database[DefaultSchemaEnumNameOrOptions['schema']]['Enums']
|
||||
: never = never,
|
||||
> = DefaultSchemaEnumNameOrOptions extends { schema: keyof Database }
|
||||
? Database[DefaultSchemaEnumNameOrOptions['schema']]['Enums'][EnumName]
|
||||
: DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema['Enums']
|
||||
? DefaultSchema['Enums'][DefaultSchemaEnumNameOrOptions]
|
||||
: never;
|
||||
|
||||
export type CompositeTypes<
|
||||
PublicCompositeTypeNameOrOptions extends
|
||||
| keyof DefaultSchema['CompositeTypes']
|
||||
| { schema: keyof Database },
|
||||
CompositeTypeName extends PublicCompositeTypeNameOrOptions extends {
|
||||
schema: keyof Database;
|
||||
}
|
||||
? keyof Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes']
|
||||
: never = never,
|
||||
> = PublicCompositeTypeNameOrOptions extends { schema: keyof Database }
|
||||
? Database[PublicCompositeTypeNameOrOptions['schema']]['CompositeTypes'][CompositeTypeName]
|
||||
: PublicCompositeTypeNameOrOptions extends keyof DefaultSchema['CompositeTypes']
|
||||
? DefaultSchema['CompositeTypes'][PublicCompositeTypeNameOrOptions]
|
||||
: never;
|
||||
|
||||
export const Constants = {
|
||||
public: {
|
||||
Enums: {},
|
||||
},
|
||||
} as const;
|
25
src/utils/supabase/utils.ts
Normal file
25
src/utils/supabase/utils.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import type { Database } from '@/utils/supabase/types';
|
||||
|
||||
// Table row types
|
||||
export type Profile = Database['public']['Tables']['profiles']['Row'];
|
||||
export type Status = Database['public']['Tables']['statuses']['Row'];
|
||||
|
||||
// Insert types
|
||||
export type ProfileInsert = Database['public']['Tables']['profiles']['Insert'];
|
||||
export type StatusInsert = Database['public']['Tables']['statuses']['Insert'];
|
||||
|
||||
// Update types
|
||||
export type ProfileUpdate = Database['public']['Tables']['profiles']['Update'];
|
||||
export type StatusUpdate = Database['public']['Tables']['statuses']['Update'];
|
||||
|
||||
// Generic helper to get any table's row type
|
||||
export type TableRow<T extends keyof Database['public']['Tables']> =
|
||||
Database['public']['Tables'][T]['Row'];
|
||||
|
||||
// Generic helper to get any table's insert type
|
||||
export type TableInsert<T extends keyof Database['public']['Tables']> =
|
||||
Database['public']['Tables'][T]['Insert'];
|
||||
|
||||
// Generic helper to get any table's update type
|
||||
export type TableUpdate<T extends keyof Database['public']['Tables']> =
|
||||
Database['public']['Tables'][T]['Update'];
|
Reference in New Issue
Block a user