feat: add Cloudflare D1 runtime support #4
+14
-3
@@ -3,13 +3,24 @@ import { drizzleAdapter } from 'better-auth/adapters/drizzle';
|
||||
import { admin } from 'better-auth/plugins';
|
||||
import { sveltekitCookies } from 'better-auth/svelte-kit';
|
||||
import { env } from '$env/dynamic/private';
|
||||
import { building } from '$app/environment';
|
||||
import { getRequestEvent } from '$app/server';
|
||||
import { db } from '$lib/server/db';
|
||||
import * as schema from '$lib/server/db/schema';
|
||||
|
||||
const buildTimeOrigin = 'http://localhost:5173';
|
||||
const buildTimeSecret = 'clearity-build-time-placeholder-secret';
|
||||
|
||||
const origin = env.ORIGIN ?? (building ? buildTimeOrigin : undefined);
|
||||
const secret = env.BETTER_AUTH_SECRET ?? (building ? buildTimeSecret : undefined);
|
||||
|
||||
if (!origin) throw new Error('ORIGIN is not set');
|
||||
if (!secret) throw new Error('BETTER_AUTH_SECRET is not set');
|
||||
|
||||
export const auth = betterAuth({
|
||||
baseURL: env.ORIGIN,
|
||||
secret: env.BETTER_AUTH_SECRET,
|
||||
database: drizzleAdapter(db, { provider: 'sqlite' }),
|
||||
baseURL: origin,
|
||||
secret,
|
||||
database: drizzleAdapter(db, { provider: 'sqlite', schema }),
|
||||
emailAndPassword: {
|
||||
enabled: true,
|
||||
disableSignUp: true
|
||||
|
||||
@@ -1,10 +1,74 @@
|
||||
import { drizzle } from 'drizzle-orm/libsql';
|
||||
import { createClient } from '@libsql/client';
|
||||
import * as schema from './schema';
|
||||
import { env } from '$env/dynamic/private';
|
||||
import { getRequestEvent } from '$app/server';
|
||||
import { createClient, type Client } from '@libsql/client';
|
||||
import { drizzle as drizzleD1, type DrizzleD1Database } from 'drizzle-orm/d1';
|
||||
import { drizzle as drizzleLibSQL, type LibSQLDatabase } from 'drizzle-orm/libsql';
|
||||
import * as schema from './schema';
|
||||
|
||||
if (!env.DATABASE_URL) throw new Error('DATABASE_URL is not set');
|
||||
type Schema = typeof schema;
|
||||
type LocalDatabase = LibSQLDatabase<Schema> & { $client: Client };
|
||||
type D1DatabaseClient = DrizzleD1Database<Schema> & { $client: D1Database };
|
||||
|
||||
export type Database = LocalDatabase;
|
||||
export type RuntimeDatabase = LocalDatabase | D1DatabaseClient;
|
||||
|
||||
let localDb: LocalDatabase | undefined;
|
||||
const d1Databases = new WeakMap<D1Database, D1DatabaseClient>();
|
||||
|
||||
function getD1Binding() {
|
||||
try {
|
||||
return getRequestEvent().platform?.env.DB;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function getLocalDb() {
|
||||
if (localDb) return localDb;
|
||||
if (!env.DATABASE_URL)
|
||||
throw new Error('DATABASE_URL is not set and no Cloudflare D1 DB binding is available');
|
||||
|
||||
const client = createClient({ url: env.DATABASE_URL });
|
||||
localDb = drizzleLibSQL(client, { schema });
|
||||
|
||||
export const db = drizzle(client, { schema });
|
||||
return localDb;
|
||||
}
|
||||
|
||||
function getD1Db(binding: D1Database) {
|
||||
const cached = d1Databases.get(binding);
|
||||
if (cached) return cached;
|
||||
|
||||
const database = drizzleD1(binding, { schema });
|
||||
d1Databases.set(binding, database);
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
export function getDb(): RuntimeDatabase {
|
||||
if (env.DATABASE_URL) return getLocalDb();
|
||||
|
||||
const d1Binding = getD1Binding();
|
||||
if (d1Binding) return getD1Db(d1Binding);
|
||||
|
||||
return getLocalDb();
|
||||
}
|
||||
|
||||
export const db = new Proxy({} as Database, {
|
||||
get(_target, property) {
|
||||
const database = getDb();
|
||||
const value = Reflect.get(database, property);
|
||||
return typeof value === 'function' ? value.bind(database) : value;
|
||||
},
|
||||
getOwnPropertyDescriptor(_target, property) {
|
||||
return Reflect.getOwnPropertyDescriptor(getDb(), property);
|
||||
},
|
||||
getPrototypeOf() {
|
||||
return Reflect.getPrototypeOf(getDb());
|
||||
},
|
||||
has(_target, property) {
|
||||
return property in getDb();
|
||||
},
|
||||
ownKeys() {
|
||||
return Reflect.ownKeys(getDb());
|
||||
}
|
||||
});
|
||||
|
||||
Vendored
+2
-4
@@ -1,11 +1,9 @@
|
||||
/* eslint-disable */
|
||||
// Generated by Wrangler by running `wrangler types` (hash: 61c64c9cd1c2465ff3a92bc5ac82d57d)
|
||||
// Generated by Wrangler by running `wrangler types` (hash: f6e835394237f01fba038726e2d4f9ae)
|
||||
// Runtime types generated with workerd@1.20260521.1 2026-05-23 nodejs_als
|
||||
interface __BaseEnv_Env {
|
||||
DB: D1Database;
|
||||
ASSETS: Fetcher;
|
||||
DATABASE_URL: string;
|
||||
ORIGIN: string;
|
||||
BETTER_AUTH_SECRET: string;
|
||||
}
|
||||
declare namespace Cloudflare {
|
||||
interface Env extends __BaseEnv_Env {}
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
"binding": "ASSETS",
|
||||
"directory": ".svelte-kit/cloudflare"
|
||||
},
|
||||
"d1_databases": [
|
||||
{
|
||||
"binding": "DB",
|
||||
"database_name": "clearity-production",
|
||||
"database_id": "<replace-with-d1-database-id>",
|
||||
"migrations_dir": "drizzle"
|
||||
}
|
||||
],
|
||||
"workers_dev": true,
|
||||
"preview_urls": true
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user