Get latest supabase migration and types

This commit is contained in:
Jared Schoeny 2025-10-11 11:01:00 -10:00
parent e6b35c4158
commit eb87506640
4 changed files with 893 additions and 2 deletions

458
src/types/db.ts Normal file
View File

@ -0,0 +1,458 @@
export type Json =
| string
| number
| boolean
| null
| { [key: string]: Json | undefined }
| Json[]
export type Database = {
// Allows to automatically instantiate createClient with right options
// instead of createClient<Database, { PostgrestVersion: 'XX' }>(URL, KEY)
__InternalSupabase: {
PostgrestVersion: "13.0.5"
}
public: {
Tables: {
hack_covers: {
Row: {
alt: string | null
hack_slug: string
id: number
position: number
url: string
}
Insert: {
alt?: string | null
hack_slug: string
id?: number
position?: number
url: string
}
Update: {
alt?: string | null
hack_slug?: string
id?: number
position?: number
url?: string
}
Relationships: [
{
foreignKeyName: "hack_covers_hack_slug_fkey"
columns: ["hack_slug"]
isOneToOne: false
referencedRelation: "hacks"
referencedColumns: ["slug"]
},
]
}
hack_tags: {
Row: {
hack_slug: string
tag_id: number
}
Insert: {
hack_slug: string
tag_id: number
}
Update: {
hack_slug?: string
tag_id?: number
}
Relationships: [
{
foreignKeyName: "hack_tags_hack_slug_fkey"
columns: ["hack_slug"]
isOneToOne: false
referencedRelation: "hacks"
referencedColumns: ["slug"]
},
{
foreignKeyName: "hack_tags_tag_id_fkey"
columns: ["tag_id"]
isOneToOne: false
referencedRelation: "tags"
referencedColumns: ["id"]
},
]
}
hacks: {
Row: {
approved: boolean
approved_at: string | null
approved_by: string | null
author: string
base_rom: string
box_art: string | null
covers: string[]
created_at: string
created_by: string
current_patch: number | null
description: string
downloads: number
estimated_release: string | null
language: string
patch_url: string
search: unknown | null
slug: string
social_links: Json | null
summary: string
tags: string[]
title: string
updated_at: string | null
version: string
}
Insert: {
approved?: boolean
approved_at?: string | null
approved_by?: string | null
author: string
base_rom: string
box_art?: string | null
covers?: string[]
created_at?: string
created_by: string
current_patch?: number | null
description: string
downloads?: number
estimated_release?: string | null
language: string
patch_url: string
search?: unknown | null
slug: string
social_links?: Json | null
summary: string
tags?: string[]
title: string
updated_at?: string | null
version: string
}
Update: {
approved?: boolean
approved_at?: string | null
approved_by?: string | null
author?: string
base_rom?: string
box_art?: string | null
covers?: string[]
created_at?: string
created_by?: string
current_patch?: number | null
description?: string
downloads?: number
estimated_release?: string | null
language?: string
patch_url?: string
search?: unknown | null
slug?: string
social_links?: Json | null
summary?: string
tags?: string[]
title?: string
updated_at?: string | null
version?: string
}
Relationships: [
{
foreignKeyName: "hacks_current_patch_fkey"
columns: ["current_patch"]
isOneToOne: false
referencedRelation: "patches"
referencedColumns: ["id"]
},
]
}
invite_codes: {
Row: {
code: string
created_at: string
used_by: string | null
}
Insert: {
code: string
created_at?: string
used_by?: string | null
}
Update: {
code?: string
created_at?: string
used_by?: string | null
}
Relationships: []
}
patch_downloads: {
Row: {
created_at: string
id: number
patch: number | null
}
Insert: {
created_at?: string
id?: number
patch?: number | null
}
Update: {
created_at?: string
id?: number
patch?: number | null
}
Relationships: [
{
foreignKeyName: "patch_downloads_patch_fkey"
columns: ["patch"]
isOneToOne: false
referencedRelation: "patches"
referencedColumns: ["id"]
},
]
}
patches: {
Row: {
bucket: string
created_at: string
filename: string
id: number
parent_hack: string | null
version: string
}
Insert: {
bucket: string
created_at?: string
filename: string
id?: number
parent_hack?: string | null
version: string
}
Update: {
bucket?: string
created_at?: string
filename?: string
id?: number
parent_hack?: string | null
version?: string
}
Relationships: [
{
foreignKeyName: "patches_parent_hack_fkey"
columns: ["parent_hack"]
isOneToOne: false
referencedRelation: "hacks"
referencedColumns: ["slug"]
},
]
}
profiles: {
Row: {
avatar_url: string | null
full_name: string | null
id: string
updated_at: string | null
username: string | null
website: string | null
}
Insert: {
avatar_url?: string | null
full_name?: string | null
id: string
updated_at?: string | null
username?: string | null
website?: string | null
}
Update: {
avatar_url?: string | null
full_name?: string | null
id?: string
updated_at?: string | null
username?: string | null
website?: string | null
}
Relationships: []
}
tags: {
Row: {
id: number
name: string
}
Insert: {
id?: number
name: string
}
Update: {
id?: number
name?: string
}
Relationships: []
}
}
Views: {
[_ in never]: never
}
Functions: {
gtrgm_compress: {
Args: { "": unknown }
Returns: unknown
}
gtrgm_decompress: {
Args: { "": unknown }
Returns: unknown
}
gtrgm_in: {
Args: { "": unknown }
Returns: unknown
}
gtrgm_options: {
Args: { "": unknown }
Returns: undefined
}
gtrgm_out: {
Args: { "": unknown }
Returns: unknown
}
is_admin: {
Args: Record<PropertyKey, never>
Returns: boolean
}
set_limit: {
Args: { "": number }
Returns: number
}
show_limit: {
Args: Record<PropertyKey, never>
Returns: number
}
show_trgm: {
Args: { "": string }
Returns: string[]
}
}
Enums: {
[_ in never]: never
}
CompositeTypes: {
[_ in never]: never
}
}
}
type DatabaseWithoutInternals = Omit<Database, "__InternalSupabase">
type DefaultSchema = DatabaseWithoutInternals[Extract<keyof Database, "public">]
export type Tables<
DefaultSchemaTableNameOrOptions extends
| keyof (DefaultSchema["Tables"] & DefaultSchema["Views"])
| { schema: keyof DatabaseWithoutInternals },
TableName extends DefaultSchemaTableNameOrOptions extends {
schema: keyof DatabaseWithoutInternals
}
? keyof (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] &
DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Views"])
: never = never,
> = DefaultSchemaTableNameOrOptions extends {
schema: keyof DatabaseWithoutInternals
}
? (DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"] &
DatabaseWithoutInternals[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 DatabaseWithoutInternals },
TableName extends DefaultSchemaTableNameOrOptions extends {
schema: keyof DatabaseWithoutInternals
}
? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"]
: never = never,
> = DefaultSchemaTableNameOrOptions extends {
schema: keyof DatabaseWithoutInternals
}
? DatabaseWithoutInternals[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 DatabaseWithoutInternals },
TableName extends DefaultSchemaTableNameOrOptions extends {
schema: keyof DatabaseWithoutInternals
}
? keyof DatabaseWithoutInternals[DefaultSchemaTableNameOrOptions["schema"]]["Tables"]
: never = never,
> = DefaultSchemaTableNameOrOptions extends {
schema: keyof DatabaseWithoutInternals
}
? DatabaseWithoutInternals[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 DatabaseWithoutInternals },
EnumName extends DefaultSchemaEnumNameOrOptions extends {
schema: keyof DatabaseWithoutInternals
}
? keyof DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"]
: never = never,
> = DefaultSchemaEnumNameOrOptions extends {
schema: keyof DatabaseWithoutInternals
}
? DatabaseWithoutInternals[DefaultSchemaEnumNameOrOptions["schema"]]["Enums"][EnumName]
: DefaultSchemaEnumNameOrOptions extends keyof DefaultSchema["Enums"]
? DefaultSchema["Enums"][DefaultSchemaEnumNameOrOptions]
: never
export type CompositeTypes<
PublicCompositeTypeNameOrOptions extends
| keyof DefaultSchema["CompositeTypes"]
| { schema: keyof DatabaseWithoutInternals },
CompositeTypeName extends PublicCompositeTypeNameOrOptions extends {
schema: keyof DatabaseWithoutInternals
}
? keyof DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"]
: never = never,
> = PublicCompositeTypeNameOrOptions extends {
schema: keyof DatabaseWithoutInternals
}
? DatabaseWithoutInternals[PublicCompositeTypeNameOrOptions["schema"]]["CompositeTypes"][CompositeTypeName]
: PublicCompositeTypeNameOrOptions extends keyof DefaultSchema["CompositeTypes"]
? DefaultSchema["CompositeTypes"][PublicCompositeTypeNameOrOptions]
: never
export const Constants = {
public: {
Enums: {},
},
} as const

View File

@ -1,8 +1,9 @@
import { createBrowserClient } from "@supabase/ssr";
import { Database } from "@/types/db";
export function createClient() {
// Create a supabase client on the browser with project's credentials
return createBrowserClient(
return createBrowserClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!
);

View File

@ -1,12 +1,13 @@
import { createServerClient } from "@supabase/ssr";
import { cookies } from "next/headers";
import { Database } from "@/types/db";
export async function createClient() {
const cookieStore = await cookies();
// Create a server's supabase client with newly configured cookie,
// which could be used to maintain user's session
return createServerClient(
return createServerClient<Database>(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY!,
{

View File

@ -0,0 +1,431 @@
revoke delete on table "public"."hack_covers" from "anon";
revoke insert on table "public"."hack_covers" from "anon";
revoke references on table "public"."hack_covers" from "anon";
revoke select on table "public"."hack_covers" from "anon";
revoke trigger on table "public"."hack_covers" from "anon";
revoke truncate on table "public"."hack_covers" from "anon";
revoke update on table "public"."hack_covers" from "anon";
revoke delete on table "public"."hack_covers" from "authenticated";
revoke insert on table "public"."hack_covers" from "authenticated";
revoke references on table "public"."hack_covers" from "authenticated";
revoke select on table "public"."hack_covers" from "authenticated";
revoke trigger on table "public"."hack_covers" from "authenticated";
revoke truncate on table "public"."hack_covers" from "authenticated";
revoke update on table "public"."hack_covers" from "authenticated";
revoke delete on table "public"."hack_covers" from "service_role";
revoke insert on table "public"."hack_covers" from "service_role";
revoke references on table "public"."hack_covers" from "service_role";
revoke select on table "public"."hack_covers" from "service_role";
revoke trigger on table "public"."hack_covers" from "service_role";
revoke truncate on table "public"."hack_covers" from "service_role";
revoke update on table "public"."hack_covers" from "service_role";
revoke delete on table "public"."hack_tags" from "anon";
revoke insert on table "public"."hack_tags" from "anon";
revoke references on table "public"."hack_tags" from "anon";
revoke select on table "public"."hack_tags" from "anon";
revoke trigger on table "public"."hack_tags" from "anon";
revoke truncate on table "public"."hack_tags" from "anon";
revoke update on table "public"."hack_tags" from "anon";
revoke delete on table "public"."hack_tags" from "authenticated";
revoke insert on table "public"."hack_tags" from "authenticated";
revoke references on table "public"."hack_tags" from "authenticated";
revoke select on table "public"."hack_tags" from "authenticated";
revoke trigger on table "public"."hack_tags" from "authenticated";
revoke truncate on table "public"."hack_tags" from "authenticated";
revoke update on table "public"."hack_tags" from "authenticated";
revoke delete on table "public"."hack_tags" from "service_role";
revoke insert on table "public"."hack_tags" from "service_role";
revoke references on table "public"."hack_tags" from "service_role";
revoke select on table "public"."hack_tags" from "service_role";
revoke trigger on table "public"."hack_tags" from "service_role";
revoke truncate on table "public"."hack_tags" from "service_role";
revoke update on table "public"."hack_tags" from "service_role";
revoke delete on table "public"."hacks" from "anon";
revoke insert on table "public"."hacks" from "anon";
revoke references on table "public"."hacks" from "anon";
revoke select on table "public"."hacks" from "anon";
revoke trigger on table "public"."hacks" from "anon";
revoke truncate on table "public"."hacks" from "anon";
revoke update on table "public"."hacks" from "anon";
revoke delete on table "public"."hacks" from "authenticated";
revoke insert on table "public"."hacks" from "authenticated";
revoke references on table "public"."hacks" from "authenticated";
revoke select on table "public"."hacks" from "authenticated";
revoke trigger on table "public"."hacks" from "authenticated";
revoke truncate on table "public"."hacks" from "authenticated";
revoke update on table "public"."hacks" from "authenticated";
revoke delete on table "public"."hacks" from "service_role";
revoke insert on table "public"."hacks" from "service_role";
revoke references on table "public"."hacks" from "service_role";
revoke select on table "public"."hacks" from "service_role";
revoke trigger on table "public"."hacks" from "service_role";
revoke truncate on table "public"."hacks" from "service_role";
revoke update on table "public"."hacks" from "service_role";
revoke delete on table "public"."profiles" from "anon";
revoke insert on table "public"."profiles" from "anon";
revoke references on table "public"."profiles" from "anon";
revoke select on table "public"."profiles" from "anon";
revoke trigger on table "public"."profiles" from "anon";
revoke truncate on table "public"."profiles" from "anon";
revoke update on table "public"."profiles" from "anon";
revoke delete on table "public"."profiles" from "authenticated";
revoke insert on table "public"."profiles" from "authenticated";
revoke references on table "public"."profiles" from "authenticated";
revoke select on table "public"."profiles" from "authenticated";
revoke trigger on table "public"."profiles" from "authenticated";
revoke truncate on table "public"."profiles" from "authenticated";
revoke update on table "public"."profiles" from "authenticated";
revoke delete on table "public"."profiles" from "service_role";
revoke insert on table "public"."profiles" from "service_role";
revoke references on table "public"."profiles" from "service_role";
revoke select on table "public"."profiles" from "service_role";
revoke trigger on table "public"."profiles" from "service_role";
revoke truncate on table "public"."profiles" from "service_role";
revoke update on table "public"."profiles" from "service_role";
revoke delete on table "public"."tags" from "anon";
revoke insert on table "public"."tags" from "anon";
revoke references on table "public"."tags" from "anon";
revoke select on table "public"."tags" from "anon";
revoke trigger on table "public"."tags" from "anon";
revoke truncate on table "public"."tags" from "anon";
revoke update on table "public"."tags" from "anon";
revoke delete on table "public"."tags" from "authenticated";
revoke insert on table "public"."tags" from "authenticated";
revoke references on table "public"."tags" from "authenticated";
revoke select on table "public"."tags" from "authenticated";
revoke trigger on table "public"."tags" from "authenticated";
revoke truncate on table "public"."tags" from "authenticated";
revoke update on table "public"."tags" from "authenticated";
revoke delete on table "public"."tags" from "service_role";
revoke insert on table "public"."tags" from "service_role";
revoke references on table "public"."tags" from "service_role";
revoke select on table "public"."tags" from "service_role";
revoke trigger on table "public"."tags" from "service_role";
revoke truncate on table "public"."tags" from "service_role";
revoke update on table "public"."tags" from "service_role";
create table "public"."invite_codes" (
"created_at" timestamp with time zone not null default now(),
"code" text not null,
"used_by" uuid
);
alter table "public"."invite_codes" enable row level security;
create table "public"."patch_downloads" (
"id" bigint generated by default as identity not null,
"created_at" timestamp with time zone not null default now(),
"patch" bigint
);
alter table "public"."patch_downloads" enable row level security;
create table "public"."patches" (
"id" bigint generated by default as identity not null,
"created_at" timestamp with time zone not null default now(),
"version" text not null,
"filename" text not null,
"bucket" text not null,
"parent_hack" text
);
alter table "public"."patches" enable row level security;
alter table "public"."hacks" add column "approved_at" timestamp without time zone;
alter table "public"."hacks" add column "approved_by" uuid;
alter table "public"."hacks" add column "current_patch" bigint;
alter table "public"."hacks" add column "estimated_release" date;
alter table "public"."hacks" add column "language" text not null;
CREATE UNIQUE INDEX invite_codes_code_key ON public.invite_codes USING btree (code);
CREATE UNIQUE INDEX invite_codes_pkey ON public.invite_codes USING btree (code);
CREATE UNIQUE INDEX patch_downloads_pkey ON public.patch_downloads USING btree (id);
CREATE UNIQUE INDEX patches_pkey ON public.patches USING btree (id);
alter table "public"."invite_codes" add constraint "invite_codes_pkey" PRIMARY KEY using index "invite_codes_pkey";
alter table "public"."patch_downloads" add constraint "patch_downloads_pkey" PRIMARY KEY using index "patch_downloads_pkey";
alter table "public"."patches" add constraint "patches_pkey" PRIMARY KEY using index "patches_pkey";
alter table "public"."hacks" add constraint "hacks_approved_by_fkey" FOREIGN KEY (approved_by) REFERENCES auth.users(id) ON DELETE SET NULL not valid;
alter table "public"."hacks" validate constraint "hacks_approved_by_fkey";
alter table "public"."hacks" add constraint "hacks_current_patch_fkey" FOREIGN KEY (current_patch) REFERENCES patches(id) ON DELETE SET NULL not valid;
alter table "public"."hacks" validate constraint "hacks_current_patch_fkey";
alter table "public"."invite_codes" add constraint "invite_codes_code_key" UNIQUE using index "invite_codes_code_key";
alter table "public"."invite_codes" add constraint "invite_codes_used_by_fkey" FOREIGN KEY (used_by) REFERENCES auth.users(id) ON DELETE CASCADE not valid;
alter table "public"."invite_codes" validate constraint "invite_codes_used_by_fkey";
alter table "public"."patch_downloads" add constraint "patch_downloads_patch_fkey" FOREIGN KEY (patch) REFERENCES patches(id) ON UPDATE CASCADE ON DELETE SET NULL not valid;
alter table "public"."patch_downloads" validate constraint "patch_downloads_patch_fkey";
alter table "public"."patches" add constraint "patches_parent_hack_fkey" FOREIGN KEY (parent_hack) REFERENCES hacks(slug) ON UPDATE CASCADE ON DELETE CASCADE not valid;
alter table "public"."patches" validate constraint "patches_parent_hack_fkey";
set check_function_bodies = off;
CREATE OR REPLACE FUNCTION public.hacks_update_guard()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
if not public.is_admin() then
if new.slug is distinct from old.slug then
raise exception 'non-admins cannot change slug';
end if;
if new.created_by is distinct from old.created_by then
raise exception 'non-admins cannot change created_by';
end if;
if new.approved is distinct from old.approved then
raise exception 'non-admins cannot change approved';
end if;
end if;
return new;
end;
$function$
;
CREATE OR REPLACE FUNCTION public.handle_new_user()
RETURNS trigger
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path TO ''
AS $function$
begin
insert into public.profiles (id, full_name, avatar_url)
values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url');
return new;
end;
$function$
;
CREATE OR REPLACE FUNCTION public.is_admin()
RETURNS boolean
LANGUAGE sql
STABLE
AS $function$
select
-- If using Supabase auth, service role bypasses RLS anyway, but keep for completeness
(current_setting('request.jwt.claims', true)::jsonb ? 'role' and
(current_setting('request.jwt.claims', true)::jsonb ->> 'role') = 'service_role')
or
(
-- Check common locations for an admin flag/role
coalesce((current_setting('request.jwt.claims', true)::jsonb #>> '{app_metadata,role}'), '') = 'admin'
or coalesce((current_setting('request.jwt.claims', true)::jsonb #>> '{user_metadata,role}'), '') = 'admin'
or coalesce((current_setting('request.jwt.claims', true)::jsonb #>> '{claims,role}'), '') = 'admin'
or coalesce((current_setting('request.jwt.claims', true)::jsonb ->> 'admin'), 'false')::boolean = true
);
$function$
;
CREATE OR REPLACE FUNCTION public.set_updated_at()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
begin
new.updated_at = now();
return new;
end;
$function$
;
create policy "Enable insert for admin users only"
on "public"."invite_codes"
as permissive
for insert
to supabase_admin
with check (true);
create policy "Allow supabase_admins to select"
on "public"."patch_downloads"
as permissive
for select
to supabase_admin
using (true);
create policy "Enable delete for users based on user_id"
on "public"."patch_downloads"
as permissive
for delete
to supabase_admin
using (true);
create policy "Enable read access for all users"
on "public"."patches"
as permissive
for select
to public
using (true);
create policy "Only allow authenticated users to create patches for hacks that"
on "public"."patches"
as permissive
for insert
to public
with check ((( SELECT auth.uid() AS uid) IN ( SELECT hack.created_by
FROM hacks hack
WHERE (hack.slug = patches.parent_hack))));
drop policy "Anyone can upload an avatar." on "storage"."objects";
drop policy "Authenticated users can upload hack boxart." on "storage"."objects";
drop policy "Authenticated users can upload hack covers." on "storage"."objects";
create policy "Anyone can upload an avatar."
on "storage"."objects"
as permissive
for insert
to authenticated
with check ((bucket_id = 'avatars'::text));
create policy "Authenticated users can upload hack boxart."
on "storage"."objects"
as permissive
for insert
to authenticated
with check ((bucket_id = 'hack-boxart'::text));
create policy "Authenticated users can upload hack covers."
on "storage"."objects"
as permissive
for insert
to authenticated
with check ((bucket_id = 'hack-covers'::text));