Making progress on rewrite. Looking into supabase cache helpers.
This commit is contained in:
23
src/utils/supabase/client.ts
Normal file
23
src/utils/supabase/client.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
'use client';
|
||||
|
||||
import { createBrowserClient } from '@supabase/ssr';
|
||||
import type { Database } from '@/utils/supabase/database.types';
|
||||
import type { SupabaseClient } from '@/utils/supabase/types';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
let client: SupabaseClient | undefined;
|
||||
|
||||
const getSupbaseClient = () => {
|
||||
if (client) return client;
|
||||
client = createBrowserClient<Database>(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
);
|
||||
return client;
|
||||
};
|
||||
|
||||
const useSupabaseClient = () => {
|
||||
return useMemo(getSupbaseClient, []);
|
||||
};
|
||||
|
||||
export { useSupabaseClient };
|
203
src/utils/supabase/database.types.ts
Normal file
203
src/utils/supabase/database.types.ts
Normal file
@@ -0,0 +1,203 @@
|
||||
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: [
|
||||
{
|
||||
foreignKeyName: 'statuses_updated_by_id_fkey';
|
||||
columns: ['updated_by_id'];
|
||||
isOneToOne: false;
|
||||
referencedRelation: 'profiles';
|
||||
referencedColumns: ['id'];
|
||||
},
|
||||
{
|
||||
foreignKeyName: 'statuses_user_id_fkey';
|
||||
columns: ['user_id'];
|
||||
isOneToOne: false;
|
||||
referencedRelation: 'profiles';
|
||||
referencedColumns: ['id'];
|
||||
},
|
||||
];
|
||||
};
|
||||
};
|
||||
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;
|
5
src/utils/supabase/index.ts
Normal file
5
src/utils/supabase/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export { useSupabaseClient } from './client';
|
||||
export { updateSession } from './middleware';
|
||||
export { useSupabaseServer } from './server';
|
||||
export type { Database } from './database.types';
|
||||
export type * from './types';
|
56
src/utils/supabase/middleware.ts
Normal file
56
src/utils/supabase/middleware.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { createServerClient } from '@supabase/ssr';
|
||||
import { type NextRequest, NextResponse } from 'next/server';
|
||||
import type { Database } from '@/utils/supabase/database.types';
|
||||
|
||||
export const updateSession = async (
|
||||
request: NextRequest,
|
||||
): Promise<NextResponse> => {
|
||||
try {
|
||||
// Create an unmodified response
|
||||
let response = NextResponse.next({
|
||||
request: {
|
||||
headers: request.headers,
|
||||
},
|
||||
});
|
||||
|
||||
const supabase = createServerClient<Database>(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
{
|
||||
cookies: {
|
||||
getAll() {
|
||||
return request.cookies.getAll();
|
||||
},
|
||||
setAll(cookiesToSet) {
|
||||
cookiesToSet.forEach(({ name, value }) =>
|
||||
request.cookies.set(name, value),
|
||||
);
|
||||
response = NextResponse.next({
|
||||
request,
|
||||
});
|
||||
cookiesToSet.forEach(({ name, value, options }) =>
|
||||
response.cookies.set(name, value, options),
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// This will refresh session if expired - required for Server Components
|
||||
// https://supabase.com/docs/guides/auth/server-side/nextjs
|
||||
const user = await supabase.auth.getUser();
|
||||
|
||||
// protected routes
|
||||
if (request.nextUrl.pathname.startsWith('/reset-password') && user.error) {
|
||||
return NextResponse.redirect(new URL('/sign-in', request.url));
|
||||
}
|
||||
|
||||
return response;
|
||||
} catch (e) {
|
||||
return NextResponse.next({
|
||||
request: {
|
||||
headers: request.headers,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
30
src/utils/supabase/server.ts
Normal file
30
src/utils/supabase/server.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
'use server';
|
||||
|
||||
import 'server-only';
|
||||
import { createServerClient } from '@supabase/ssr';
|
||||
import type { Database } from '@/utils/supabase/database.types';
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
export const useSupabaseServer = async () => {
|
||||
const cookieStore = await cookies();
|
||||
return createServerClient<Database>(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
{
|
||||
cookies: {
|
||||
getAll() {
|
||||
return cookieStore.getAll();
|
||||
},
|
||||
setAll(cookiesToSet) {
|
||||
try {
|
||||
cookiesToSet.forEach(({ name, value, options }) => {
|
||||
cookieStore.set(name, value, options);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Error setting cookies: ${error as string}`);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
30
src/utils/supabase/types.ts
Normal file
30
src/utils/supabase/types.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import type { Database } from '@/utils/supabase/database.types';
|
||||
import type { SupabaseClient as SBClient } from '@supabase/supabase-js'
|
||||
|
||||
export type SupabaseClient = SBClient<Database>;
|
||||
|
||||
export type { User } from '@supabase/supabase-js';
|
||||
|
||||
// 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