Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/server/src/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as schema from './schema';
import postgres from 'postgres';

export const createDb = (url: string) => {
console.log('0'.repeat(10), 'Creating a new DB Connection');
const conn = postgres(url);
const db = drizzle(conn, { schema });
return db;
Expand Down
65 changes: 15 additions & 50 deletions apps/server/src/lib/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ import { eq } from 'drizzle-orm';
import { createDb } from '../db';

const connectionHandlerHook = async (account: Account) => {
const c = getContext<HonoContext>();

if (!account.accessToken || !account.refreshToken) {
console.error('Missing Access/Refresh Tokens', { account });
throw new APIError('EXPECTATION_FAILED', { message: 'Missing Access/Refresh Tokens' });
Expand Down Expand Up @@ -58,27 +56,13 @@ const connectionHandlerHook = async (account: Account) => {
expiresAt: new Date(Date.now() + (account.accessTokenExpiresAt?.getTime() || 3600000)),
};

const connectionId = crypto.randomUUID();

const [result] = await c.var.db
.insert(connection)
.values({
providerId: account.providerId as 'google' | 'microsoft',
id: connectionId,
email: userInfo.address,
userId: account.userId,
createdAt: new Date(),
updatedAt: new Date(),
...updatingInfo,
})
.onConflictDoUpdate({
target: [connection.email, connection.userId],
set: {
...updatingInfo,
updatedAt: new Date(),
},
})
.returning({ id: connection.id });
const db = env.ZERO_DB.get(env.ZERO_DB.idFromName('global-db'));
const [result] = await db.createConnection(
account.providerId as EProviders,
userInfo.address,
account.userId,
updatingInfo,
);

if (env.GOOGLE_S_ACCOUNT && env.GOOGLE_S_ACCOUNT !== '{}') {
await env.subscribe_queue.send({
Expand All @@ -89,8 +73,8 @@ const connectionHandlerHook = async (account: Account) => {
};

export const createAuth = () => {
const c = getContext<HonoContext>();
const twilioClient = twilio();
const db = env.ZERO_DB.get(env.ZERO_DB.idFromName('global-db'));

return betterAuth({
plugins: [
Expand All @@ -114,9 +98,7 @@ export const createAuth = () => {
enabled: true,
beforeDelete: async (user, request) => {
if (!request) throw new APIError('BAD_REQUEST', { message: 'Request object is missing' });
const connections = await c.var.db.query.connection.findMany({
where: eq(connection.userId, user.id),
});
const connections = await db.findManyConnections(user.id);

const revokedAccounts = (
await Promise.allSettled(
Expand Down Expand Up @@ -149,14 +131,7 @@ export const createAuth = () => {
console.log('Failed to revoke some accounts');
}

await c.var.db.transaction(async (tx) => {
await tx.delete(connection).where(eq(connection.userId, user.id));
await tx.delete(account).where(eq(account.userId, user.id));
await tx.delete(session).where(eq(session.userId, user.id));
await tx.delete(userSettings).where(eq(userSettings.userId, user.id));
await tx.delete(_user).where(eq(_user.id, user.id));
await tx.delete(userHotkeys).where(eq(userHotkeys.userId, user.id));
});
await db.deleteUser(user.id);
},
},
},
Expand Down Expand Up @@ -191,7 +166,7 @@ export const createAuth = () => {
sendOnSignUp: false,
autoSignInAfterVerification: true,
sendVerificationEmail: async ({ user, token }) => {
const verificationUrl = `${c.env.VITE_PUBLIC_APP_URL}/api/auth/verify-email?token=${token}&callbackURL=/settings/connections`;
const verificationUrl = `${env.VITE_PUBLIC_APP_URL}/api/auth/verify-email?token=${token}&callbackURL=/settings/connections`;

await resend().emails.send({
from: '0.email <onboarding@0.email>',
Expand All @@ -213,11 +188,7 @@ export const createAuth = () => {
const newSession = ctx.context.newSession;
if (newSession) {
// Check if user already has settings
const [existingSettings] = await c.var.db
.select()
.from(userSettings)
.where(eq(userSettings.userId, newSession.user.id))
.limit(1);
const existingSettings = await db.findUserSettings(newSession.user.id);

if (!existingSettings) {
// get timezone from vercel's header
Expand All @@ -228,15 +199,9 @@ export const createAuth = () => {
? headerTimezone
: getBrowserTimezone();
// write default settings against the user
await c.var.db.insert(userSettings).values({
id: crypto.randomUUID(),
userId: newSession.user.id,
settings: {
...defaultUserSettings,
timezone,
},
createdAt: new Date(),
updatedAt: new Date(),
await db.insertUserSettings(newSession.user.id, {
...defaultUserSettings,
timezone,
});
}
}
Expand Down
9 changes: 3 additions & 6 deletions apps/server/src/lib/driver/utils.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { getActiveConnection } from '../server-utils';
import { getContext } from 'hono/context-storage';
import type { gmail_v1 } from '@googleapis/gmail';
import { connection } from '../../db/schema';
import type { HonoContext } from '../../ctx';
import { env } from 'cloudflare:workers';
import { createDriver } from '../driver';
import { toByteArray } from 'base64-js';
import { and, eq } from 'drizzle-orm';

export const FatalErrors = ['invalid_grant'];

export const deleteActiveConnection = async () => {
Expand All @@ -17,9 +15,8 @@ export const deleteActiveConnection = async () => {
if (!session) return console.log('No session found');
try {
await c.var.auth.api.signOut({ headers: c.req.raw.headers });
await c.var.db
.delete(connection)
.where(and(eq(connection.userId, session.user.id), eq(connection.id, activeConnection.id)));
const db = env.ZERO_DB.get(env.ZERO_DB.idFromName('global-db'));
await db.deleteActiveConnection(session.user.id, activeConnection.id);
} catch (error) {
console.error('Server: Error deleting connection:', error);
throw error;
Expand Down
15 changes: 5 additions & 10 deletions apps/server/src/lib/factories/base-subscription.factory.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { defaultLabels, EProviders, type AppContext } from '../../types';
import { getContext } from 'hono/context-storage';
import { connection } from '../../db/schema';
import type { HonoContext } from '../../ctx';
import { env } from 'cloudflare:workers';
import { createDb } from '../../db';

export interface SubscriptionData {
connectionId?: string;
Expand All @@ -23,15 +24,9 @@ export abstract class BaseSubscriptionFactory {

abstract verifyToken(token: string): Promise<boolean>;

protected async getConnectionFromDb(connectionId: string): Promise<any> {
const db = createDb(env.HYPERDRIVE.connectionString);
const { eq } = await import('drizzle-orm');

const [connectionData] = await db
.select()
.from(connection)
.where(eq(connection.id, connectionId));

protected async getConnectionFromDb(connectionId: string) {
const db = env.ZERO_DB.get(env.ZERO_DB.idFromName('global-db'));
const connectionData = await db.findConnectionById(connectionId);
return connectionData;
}

Expand Down
22 changes: 9 additions & 13 deletions apps/server/src/lib/server-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,22 @@ import { and, eq } from 'drizzle-orm';

export const getActiveConnection = async () => {
const c = getContext<HonoContext>();
const { sessionUser, db } = c.var;
const { sessionUser } = c.var;
if (!sessionUser) throw new Error('Session Not Found');

const userData = await db.query.user.findFirst({
where: eq(user.id, sessionUser.id),
});
const db = env.ZERO_DB.get(env.ZERO_DB.idFromName('global-db'));

const userData = await db.findUser(sessionUser.id);

if (userData?.defaultConnectionId) {
const activeConnection = await db.query.connection.findFirst({
where: and(
eq(connection.userId, sessionUser.id),
eq(connection.id, userData.defaultConnectionId),
),
});
const activeConnection = await db.findUserConnection(
sessionUser.id,
userData.defaultConnectionId,
);
if (activeConnection) return activeConnection;
}

const firstConnection = await db.query.connection.findFirst({
where: and(eq(connection.userId, sessionUser.id)),
});
const firstConnection = await db.findFirstConnection(sessionUser.id);
if (!firstConnection) {
console.error(`No connections found for user ${sessionUser.id}`);
throw new Error('No connections found for user');
Expand Down
Loading