initial commit
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { createClient, SupabaseClient } from '@supabase/supabase-js';
|
||||
|
||||
let _admin: SupabaseClient | null = null;
|
||||
|
||||
export function getSupabaseAdmin(): SupabaseClient {
|
||||
if (_admin) return _admin;
|
||||
const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const key = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
||||
if (!url || !key) {
|
||||
throw new Error('Supabase admin env not configured');
|
||||
}
|
||||
_admin = createClient(url, key, {
|
||||
auth: { autoRefreshToken: false, persistSession: false },
|
||||
});
|
||||
return _admin;
|
||||
}
|
||||
|
||||
export function getSupabaseAnon(): SupabaseClient {
|
||||
const url = process.env.NEXT_PUBLIC_SUPABASE_URL;
|
||||
const key = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;
|
||||
if (!url || !key) {
|
||||
throw new Error('Supabase anon env not configured');
|
||||
}
|
||||
return createClient(url, key, {
|
||||
auth: { autoRefreshToken: false, persistSession: false },
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import { createBrowserClient } from '@supabase/ssr';
|
||||
|
||||
export function createSupabaseBrowserClient() {
|
||||
return createBrowserClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import { createServerClient } from '@supabase/ssr';
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
export function createSupabaseServerClient() {
|
||||
const cookieStore = cookies();
|
||||
return createServerClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
{
|
||||
cookies: {
|
||||
getAll() {
|
||||
return cookieStore.getAll();
|
||||
},
|
||||
setAll(toSet) {
|
||||
try {
|
||||
toSet.forEach(({ name, value, options }) => {
|
||||
cookieStore.set(name, value, options);
|
||||
});
|
||||
} catch {
|
||||
// Called from a Server Component — middleware will refresh.
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
export const RESERVED_SUBDOMAINS = new Set([
|
||||
'app',
|
||||
'api',
|
||||
'www',
|
||||
'admin',
|
||||
'auth',
|
||||
'mail',
|
||||
'static',
|
||||
]);
|
||||
|
||||
const SUBDOMAIN_RE = /^[a-z0-9-]{3,32}$/;
|
||||
|
||||
export function validateSubdomain(input: unknown):
|
||||
| { ok: true; value: string }
|
||||
| { ok: false; error: string } {
|
||||
if (typeof input !== 'string') {
|
||||
return { ok: false, error: 'subdomain must be a string' };
|
||||
}
|
||||
const value = input.trim().toLowerCase();
|
||||
if (!SUBDOMAIN_RE.test(value)) {
|
||||
return {
|
||||
ok: false,
|
||||
error: 'subdomain must be 3–32 chars, lowercase a–z, 0–9, hyphen',
|
||||
};
|
||||
}
|
||||
if (RESERVED_SUBDOMAINS.has(value)) {
|
||||
return { ok: false, error: `'${value}' is reserved` };
|
||||
}
|
||||
return { ok: true, value };
|
||||
}
|
||||
Reference in New Issue
Block a user