RLS policies implementeren, Demo auth flow
This commit is contained in:
162
lib/auth/client.ts
Normal file
162
lib/auth/client.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* Supabase Auth Client Utilities
|
||||
*
|
||||
* Client-side auth helpers for login, logout, and session management
|
||||
*/
|
||||
|
||||
import { createBrowserClient } from '@supabase/ssr'
|
||||
import type { Database } from '@/lib/database.types'
|
||||
|
||||
/**
|
||||
* Create Supabase client for browser/client-side use
|
||||
*/
|
||||
export function createClient() {
|
||||
return createBrowserClient<Database>(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Send magic link to user's email
|
||||
* Auto-creates account if user doesn't exist
|
||||
*/
|
||||
export async function loginWithMagicLink(email: string) {
|
||||
const supabase = createClient()
|
||||
|
||||
const { data, error } = await supabase.auth.signInWithOtp({
|
||||
email,
|
||||
options: {
|
||||
emailRedirectTo: `${window.location.origin}/auth/callback`,
|
||||
shouldCreateUser: true, // Auto-create account on first login
|
||||
}
|
||||
})
|
||||
|
||||
if (error) throw error
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'Check je email voor de magic link!',
|
||||
data
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Login with email + password (for demo accounts)
|
||||
*/
|
||||
export async function loginWithPassword(email: string, password: string) {
|
||||
const supabase = createClient()
|
||||
|
||||
const { data, error } = await supabase.auth.signInWithPassword({
|
||||
email,
|
||||
password
|
||||
})
|
||||
|
||||
if (error) throw error
|
||||
|
||||
return {
|
||||
success: true,
|
||||
user: data.user,
|
||||
session: data.session
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout current user
|
||||
*/
|
||||
export async function logout() {
|
||||
const supabase = createClient()
|
||||
const { error } = await supabase.auth.signOut()
|
||||
|
||||
if (error) throw error
|
||||
|
||||
// Redirect to login
|
||||
window.location.href = '/login'
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current session
|
||||
*/
|
||||
export async function getSession() {
|
||||
const supabase = createClient()
|
||||
const { data: { session }, error } = await supabase.auth.getSession()
|
||||
|
||||
if (error) throw error
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current user
|
||||
*/
|
||||
export async function getUser() {
|
||||
const supabase = createClient()
|
||||
const { data: { user }, error } = await supabase.auth.getUser()
|
||||
|
||||
if (error) throw error
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is authenticated
|
||||
*/
|
||||
export async function isAuthenticated() {
|
||||
const session = await getSession()
|
||||
return !!session
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to auth state changes
|
||||
*/
|
||||
export function onAuthStateChange(
|
||||
callback: (event: string, session: any) => void
|
||||
) {
|
||||
const supabase = createClient()
|
||||
|
||||
const { data: { subscription } } = supabase.auth.onAuthStateChange(
|
||||
callback
|
||||
)
|
||||
|
||||
return subscription
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current user is a demo user
|
||||
*/
|
||||
export async function isDemoUser(): Promise<boolean> {
|
||||
const supabase = createClient()
|
||||
const user = await getUser()
|
||||
|
||||
if (!user) return false
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('demo_users')
|
||||
.select('id')
|
||||
.eq('user_id', user.id)
|
||||
.single()
|
||||
|
||||
if (error) return false
|
||||
|
||||
return !!data
|
||||
}
|
||||
|
||||
/**
|
||||
* Get demo user access level
|
||||
*/
|
||||
export async function getDemoAccessLevel(): Promise<'read_only' | 'interactive' | 'presenter' | null> {
|
||||
const supabase = createClient()
|
||||
const user = await getUser()
|
||||
|
||||
if (!user) return null
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('demo_users')
|
||||
.select('access_level')
|
||||
.eq('user_id', user.id)
|
||||
.single()
|
||||
|
||||
if (error) return null
|
||||
|
||||
return data.access_level as 'read_only' | 'interactive' | 'presenter'
|
||||
}
|
||||
154
lib/auth/server.ts
Normal file
154
lib/auth/server.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Supabase Auth Server Utilities
|
||||
*
|
||||
* Server-side auth helpers for API routes, middleware, and server components
|
||||
*/
|
||||
|
||||
import { createServerClient } from '@supabase/ssr'
|
||||
import { cookies } from 'next/headers'
|
||||
import type { Database } from '@/lib/database.types'
|
||||
|
||||
/**
|
||||
* Create Supabase client for server-side use
|
||||
* Handles cookies for session management
|
||||
*/
|
||||
export async function createClient() {
|
||||
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 {
|
||||
// The `setAll` method was called from a Server Component.
|
||||
// This can be ignored if you have middleware refreshing
|
||||
// user sessions.
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current session (server-side)
|
||||
*/
|
||||
export async function getSession() {
|
||||
const supabase = await createClient()
|
||||
const { data: { session }, error } = await supabase.auth.getSession()
|
||||
|
||||
if (error) throw error
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current user (server-side)
|
||||
*/
|
||||
export async function getUser() {
|
||||
const supabase = await createClient()
|
||||
const { data: { user }, error } = await supabase.auth.getUser()
|
||||
|
||||
if (error) throw error
|
||||
|
||||
return user
|
||||
}
|
||||
|
||||
/**
|
||||
* Require authentication - throws if not authenticated
|
||||
* Use in API routes and server actions
|
||||
*/
|
||||
export async function requireAuth() {
|
||||
const session = await getSession()
|
||||
|
||||
if (!session) {
|
||||
throw new Error('Authentication required')
|
||||
}
|
||||
|
||||
return session
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is authenticated (server-side)
|
||||
*/
|
||||
export async function isAuthenticated() {
|
||||
const session = await getSession()
|
||||
return !!session
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current user is a demo user (server-side)
|
||||
*/
|
||||
export async function isDemoUser(): Promise<boolean> {
|
||||
const supabase = await createClient()
|
||||
const user = await getUser()
|
||||
|
||||
if (!user) return false
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('demo_users')
|
||||
.select('id')
|
||||
.eq('user_id', user.id)
|
||||
.single()
|
||||
|
||||
if (error) return false
|
||||
|
||||
return !!data
|
||||
}
|
||||
|
||||
/**
|
||||
* Get demo user info (server-side)
|
||||
*/
|
||||
export async function getDemoUserInfo() {
|
||||
const supabase = await createClient()
|
||||
const user = await getUser()
|
||||
|
||||
if (!user) return null
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('demo_users')
|
||||
.select('*')
|
||||
.eq('user_id', user.id)
|
||||
.single()
|
||||
|
||||
if (error) return null
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if demo user has write access
|
||||
*/
|
||||
export async function canWrite(): Promise<boolean> {
|
||||
const demoInfo = await getDemoUserInfo()
|
||||
|
||||
// Non-demo users can write
|
||||
if (!demoInfo) return true
|
||||
|
||||
// Only 'interactive' and 'presenter' demo users can write
|
||||
return ['interactive', 'presenter'].includes(demoInfo.access_level)
|
||||
}
|
||||
|
||||
/**
|
||||
* Track demo user login
|
||||
*/
|
||||
export async function trackDemoLogin(userId: string) {
|
||||
const supabase = await createClient()
|
||||
|
||||
await supabase
|
||||
.from('demo_users')
|
||||
.update({
|
||||
usage_count: supabase.rpc('increment', { row_id: userId }),
|
||||
last_login_at: new Date().toISOString()
|
||||
})
|
||||
.eq('user_id', userId)
|
||||
}
|
||||
@@ -3,13 +3,19 @@
|
||||
*
|
||||
* Loads JSON content files from the content directory structure.
|
||||
* Supports server-side loading with TypeScript type safety.
|
||||
* Also supports loading and parsing markdown files.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const manifesto = await getContent<ManifestoContent>('nl', 'manifesto')
|
||||
* const markdownSections = await getMarkdownContent('docs/manifesto.md')
|
||||
* ```
|
||||
*/
|
||||
|
||||
import { readFile } from 'fs/promises'
|
||||
import { join } from 'path'
|
||||
import { markdownToSections } from './markdown-parser'
|
||||
|
||||
export async function getContent<T>(
|
||||
locale: string = 'nl',
|
||||
file: string
|
||||
@@ -23,6 +29,27 @@ export async function getContent<T>(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and parse markdown file to ManifestoSection format
|
||||
* Useful for converting manifesto.md to React components
|
||||
*/
|
||||
export async function getMarkdownContent(
|
||||
filePath: string
|
||||
): Promise<Array<{
|
||||
id: string
|
||||
type: 'paragraph'
|
||||
content: string
|
||||
}>> {
|
||||
try {
|
||||
const fullPath = join(process.cwd(), filePath)
|
||||
const markdown = await readFile(fullPath, 'utf-8')
|
||||
return markdownToSections(markdown)
|
||||
} catch (error) {
|
||||
console.error(`Failed to load markdown: ${filePath}`, error)
|
||||
throw new Error(`Markdown file not found: ${filePath}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe content loader with fallback
|
||||
*
|
||||
|
||||
62
lib/content/markdown-parser.ts
Normal file
62
lib/content/markdown-parser.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Markdown Parser Utility
|
||||
*
|
||||
* Simple markdown parser for converting manifesto.md content
|
||||
* to React components with proper typography.
|
||||
*
|
||||
* This is a lightweight parser for basic markdown features:
|
||||
* - Paragraphs
|
||||
* - Line breaks
|
||||
* - Basic formatting (bold, italic)
|
||||
*/
|
||||
|
||||
export interface ParsedMarkdown {
|
||||
paragraphs: string[]
|
||||
metadata?: Record<string, string>
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse markdown content into structured format
|
||||
* Splits content by double line breaks into paragraphs
|
||||
*/
|
||||
export function parseMarkdown(markdown: string): ParsedMarkdown {
|
||||
// Split by double line breaks or single line breaks followed by empty line
|
||||
const paragraphs = markdown
|
||||
.split(/\n\s*\n/)
|
||||
.map((para) => para.trim())
|
||||
.filter((para) => para.length > 0)
|
||||
|
||||
return {
|
||||
paragraphs,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert markdown paragraphs to ManifestoSection format
|
||||
* This allows markdown content to be used with existing components
|
||||
*/
|
||||
export function markdownToSections(markdown: string): Array<{
|
||||
id: string
|
||||
type: 'paragraph'
|
||||
content: string
|
||||
}> {
|
||||
const parsed = parseMarkdown(markdown)
|
||||
|
||||
return parsed.paragraphs.map((content, index) => ({
|
||||
id: `paragraph-${index + 1}`,
|
||||
type: 'paragraph' as const,
|
||||
content: content.trim(),
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple markdown renderer for inline formatting
|
||||
* Converts **bold** and *italic* to HTML
|
||||
*/
|
||||
export function renderMarkdownInline(text: string): string {
|
||||
return text
|
||||
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
||||
.replace(/\*(.+?)\*/g, '<em>$1</em>')
|
||||
.replace(/`(.+?)`/g, '<code>$1</code>')
|
||||
}
|
||||
|
||||
365
lib/database.types.ts
Normal file
365
lib/database.types.ts
Normal file
@@ -0,0 +1,365 @@
|
||||
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: {
|
||||
ai_events: {
|
||||
Row: {
|
||||
client_id: string | null
|
||||
created_at: string
|
||||
duration_ms: number
|
||||
id: string
|
||||
kind: string
|
||||
note_id: string | null
|
||||
request: Json
|
||||
response: Json
|
||||
}
|
||||
Insert: {
|
||||
client_id?: string | null
|
||||
created_at?: string
|
||||
duration_ms?: number
|
||||
id?: string
|
||||
kind: string
|
||||
note_id?: string | null
|
||||
request?: Json
|
||||
response?: Json
|
||||
}
|
||||
Update: {
|
||||
client_id?: string | null
|
||||
created_at?: string
|
||||
duration_ms?: number
|
||||
id?: string
|
||||
kind?: string
|
||||
note_id?: string | null
|
||||
request?: Json
|
||||
response?: Json
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "ai_events_client_id_fkey"
|
||||
columns: ["client_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "clients"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "ai_events_note_id_fkey"
|
||||
columns: ["note_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "intake_notes"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
clients: {
|
||||
Row: {
|
||||
birth_date: string
|
||||
created_at: string
|
||||
first_name: string
|
||||
id: string
|
||||
last_name: string
|
||||
updated_at: string
|
||||
}
|
||||
Insert: {
|
||||
birth_date: string
|
||||
created_at?: string
|
||||
first_name: string
|
||||
id?: string
|
||||
last_name: string
|
||||
updated_at?: string
|
||||
}
|
||||
Update: {
|
||||
birth_date?: string
|
||||
created_at?: string
|
||||
first_name?: string
|
||||
id?: string
|
||||
last_name?: string
|
||||
updated_at?: string
|
||||
}
|
||||
Relationships: []
|
||||
}
|
||||
intake_notes: {
|
||||
Row: {
|
||||
author: string | null
|
||||
client_id: string
|
||||
content_json: Json
|
||||
content_text: string | null
|
||||
created_at: string
|
||||
id: string
|
||||
tag: string | null
|
||||
title: string | null
|
||||
updated_at: string
|
||||
}
|
||||
Insert: {
|
||||
author?: string | null
|
||||
client_id: string
|
||||
content_json?: Json
|
||||
content_text?: string | null
|
||||
created_at?: string
|
||||
id?: string
|
||||
tag?: string | null
|
||||
title?: string | null
|
||||
updated_at?: string
|
||||
}
|
||||
Update: {
|
||||
author?: string | null
|
||||
client_id?: string
|
||||
content_json?: Json
|
||||
content_text?: string | null
|
||||
created_at?: string
|
||||
id?: string
|
||||
tag?: string | null
|
||||
title?: string | null
|
||||
updated_at?: string
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "intake_notes_client_id_fkey"
|
||||
columns: ["client_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "clients"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
problem_profiles: {
|
||||
Row: {
|
||||
category: string
|
||||
client_id: string
|
||||
created_at: string
|
||||
id: string
|
||||
remarks: string | null
|
||||
severity: string
|
||||
source_note_id: string | null
|
||||
updated_at: string
|
||||
}
|
||||
Insert: {
|
||||
category: string
|
||||
client_id: string
|
||||
created_at?: string
|
||||
id?: string
|
||||
remarks?: string | null
|
||||
severity: string
|
||||
source_note_id?: string | null
|
||||
updated_at?: string
|
||||
}
|
||||
Update: {
|
||||
category?: string
|
||||
client_id?: string
|
||||
created_at?: string
|
||||
id?: string
|
||||
remarks?: string | null
|
||||
severity?: string
|
||||
source_note_id?: string | null
|
||||
updated_at?: string
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "problem_profiles_client_id_fkey"
|
||||
columns: ["client_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "clients"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
{
|
||||
foreignKeyName: "problem_profiles_source_note_id_fkey"
|
||||
columns: ["source_note_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "intake_notes"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
treatment_plans: {
|
||||
Row: {
|
||||
client_id: string
|
||||
created_at: string
|
||||
created_by: string | null
|
||||
id: string
|
||||
plan: Json
|
||||
published_at: string | null
|
||||
status: string
|
||||
updated_at: string
|
||||
version: number
|
||||
}
|
||||
Insert: {
|
||||
client_id: string
|
||||
created_at?: string
|
||||
created_by?: string | null
|
||||
id?: string
|
||||
plan?: Json
|
||||
published_at?: string | null
|
||||
status?: string
|
||||
updated_at?: string
|
||||
version?: number
|
||||
}
|
||||
Update: {
|
||||
client_id?: string
|
||||
created_at?: string
|
||||
created_by?: string | null
|
||||
id?: string
|
||||
plan?: Json
|
||||
published_at?: string | null
|
||||
status?: string
|
||||
updated_at?: string
|
||||
version?: number
|
||||
}
|
||||
Relationships: [
|
||||
{
|
||||
foreignKeyName: "treatment_plans_client_id_fkey"
|
||||
columns: ["client_id"]
|
||||
isOneToOne: false
|
||||
referencedRelation: "clients"
|
||||
referencedColumns: ["id"]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
Views: {
|
||||
[_ in never]: never
|
||||
}
|
||||
Functions: {
|
||||
[_ in never]: never
|
||||
}
|
||||
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
|
||||
Reference in New Issue
Block a user