diff --git a/actions/addLeafletToHome.ts b/actions/addLeafletToHome.ts index 41cfb7a1..af8a64e4 100644 --- a/actions/addLeafletToHome.ts +++ b/actions/addLeafletToHome.ts @@ -1,25 +1,13 @@ "use server"; -import { drizzle } from "drizzle-orm/postgres-js"; -import { - entities, - identities, - permission_tokens, - permission_token_rights, - entity_sets, - facts, - permission_token_on_homepage, - email_auth_tokens, -} from "drizzle/schema"; -import { redirect } from "next/navigation"; -import postgres from "postgres"; -import { v7 } from "uuid"; -import { sql, eq, and } from "drizzle-orm"; +import { drizzle } from "drizzle-orm/node-postgres"; +import { sql } from "drizzle-orm"; import { cookies } from "next/headers"; +import { pool } from "supabase/pool"; export async function addLeafletToHome(leaflet: string) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); let auth_token = (await cookies()).get("auth_token")?.value; + const client = await pool.connect(); const db = drizzle(client); await db.transaction(async (tx) => { if (auth_token) { @@ -40,7 +28,6 @@ export async function addLeafletToHome(leaflet: string) { return; }); - - client.end(); + client.release(); return; } diff --git a/actions/createIdentity.ts b/actions/createIdentity.ts index 1b0eed25..4d402a7b 100644 --- a/actions/createIdentity.ts +++ b/actions/createIdentity.ts @@ -1,19 +1,16 @@ -import { PostgresJsDatabase } from "drizzle-orm/postgres-js"; import { entities, permission_tokens, permission_token_rights, entity_sets, - facts, identities, } from "drizzle/schema"; -import { redirect } from "next/navigation"; -import postgres from "postgres"; import { v7 } from "uuid"; -import { sql } from "drizzle-orm"; -import { cookies } from "next/headers"; +import { PgTransaction } from "drizzle-orm/pg-core"; +import { NodePgDatabase } from "drizzle-orm/node-postgres"; + export async function createIdentity( - db: PostgresJsDatabase, + db: NodePgDatabase, data?: { email?: string; atp_did?: string }, ) { return db.transaction(async (tx) => { diff --git a/actions/createNewLeaflet.ts b/actions/createNewLeaflet.ts index ec825f78..c94fa9f1 100644 --- a/actions/createNewLeaflet.ts +++ b/actions/createNewLeaflet.ts @@ -1,6 +1,6 @@ "use server"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { entities, identities, @@ -16,6 +16,7 @@ import postgres from "postgres"; import { v7 } from "uuid"; import { sql, eq, and } from "drizzle-orm"; import { cookies } from "next/headers"; +import { pool } from "supabase/pool"; export async function createNewLeaflet({ pageType, @@ -26,8 +27,8 @@ export async function createNewLeaflet({ redirectUser: boolean; firstBlockType?: "h1" | "text"; }) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); let auth_token = (await cookies()).get("auth_token")?.value; + const client = await pool.connect(); const db = drizzle(client); let { permissionToken } = await db.transaction(async (tx) => { // Create a new entity set @@ -156,7 +157,7 @@ export async function createNewLeaflet({ return { permissionToken, rights, root_entity, entity_set }; }); - client.end(); + client.release(); if (redirectUser) redirect(`/${permissionToken.id}?focusFirstBlock`); return permissionToken.id; } diff --git a/actions/createNewLeafletFromTemplate.ts b/actions/createNewLeafletFromTemplate.ts index d237d87c..cbbcf8ac 100644 --- a/actions/createNewLeafletFromTemplate.ts +++ b/actions/createNewLeafletFromTemplate.ts @@ -1,9 +1,7 @@ "use server"; import { createServerClient } from "@supabase/ssr"; -import { drizzle } from "drizzle-orm/postgres-js"; -import { NextRequest } from "next/server"; -import postgres from "postgres"; +import { drizzle } from "drizzle-orm/node-postgres"; import type { Fact } from "src/replicache"; import type { Attribute } from "src/replicache/attributes"; import { Database } from "supabase/database.types"; @@ -19,6 +17,7 @@ import { import { sql } from "drizzle-orm"; import { redirect } from "next/navigation"; import { cookies } from "next/headers"; +import { pool } from "supabase/pool"; let supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, @@ -84,7 +83,7 @@ export async function createNewLeafletFromTemplate( }), ); - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); let { permissionToken } = await db.transaction(async (tx) => { @@ -138,7 +137,7 @@ export async function createNewLeafletFromTemplate( return { permissionToken, rights, entity_set }; }); - client.end(); + client.release(); if (redirectUser) redirect(`/${permissionToken.id}`); return { id: permissionToken.id, error: null } as const; } diff --git a/actions/deleteLeaflet.ts b/actions/deleteLeaflet.ts index 04060fa1..5584a325 100644 --- a/actions/deleteLeaflet.ts +++ b/actions/deleteLeaflet.ts @@ -1,21 +1,17 @@ "use server"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { entities, permission_tokens, permission_token_rights, } from "drizzle/schema"; -import { redirect } from "next/navigation"; -import postgres from "postgres"; -import { v7 } from "uuid"; -import { eq, sql } from "drizzle-orm"; -import { cookies } from "next/headers"; +import { eq } from "drizzle-orm"; import { PermissionToken } from "src/replicache"; -import { revalidatePath } from "next/cache"; +import { pool } from "supabase/pool"; export async function deleteLeaflet(permission_token: PermissionToken) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); await db.transaction(async (tx) => { let [token] = await tx @@ -35,6 +31,6 @@ export async function deleteLeaflet(permission_token: PermissionToken) { .delete(permission_tokens) .where(eq(permission_tokens.id, permission_token.id)); }); - client.end(); + client.release(); return; } diff --git a/actions/emailAuth.ts b/actions/emailAuth.ts index 1746ca95..da26b75f 100644 --- a/actions/emailAuth.ts +++ b/actions/emailAuth.ts @@ -1,13 +1,14 @@ "use server"; import { randomBytes } from "crypto"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import postgres from "postgres"; import { email_auth_tokens, identities } from "drizzle/schema"; import { and, eq } from "drizzle-orm"; import { cookies } from "next/headers"; import { createIdentity } from "./createIdentity"; import { setAuthToken } from "src/auth"; +import { pool } from "supabase/pool"; async function sendAuthCode(email: string, code: string) { if (process.env.NODE_ENV === "development") { @@ -42,7 +43,7 @@ ${code} export async function requestAuthEmailToken(emailNonNormalized: string) { let email = emailNonNormalized.toLowerCase(); - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); const code = randomBytes(3).toString("hex").toUpperCase(); @@ -60,12 +61,12 @@ export async function requestAuthEmailToken(emailNonNormalized: string) { await sendAuthCode(email, code); - client.end(); + client.release(); return token.id; } export async function confirmEmailAuthToken(tokenId: string, code: string) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); const [token] = await db @@ -74,17 +75,17 @@ export async function confirmEmailAuthToken(tokenId: string, code: string) { .where(eq(email_auth_tokens.id, tokenId)); if (!token || !token.email) { - client.end(); + client.release(); return null; } if (token.confirmation_code !== code) { - client.end(); + client.release(); return null; } if (token.confirmed) { - client.end(); + client.release(); return null; } let authToken = (await cookies()).get("auth_token"); @@ -102,7 +103,7 @@ export async function confirmEmailAuthToken(tokenId: string, code: string) { .update(identities) .set({ email: token.email }) .where(eq(identities.id, existingToken.identities.id)); - client.end(); + client.release(); return existingToken; } } @@ -135,6 +136,6 @@ export async function confirmEmailAuthToken(tokenId: string, code: string) { await setAuthToken(confirmedToken.id); - client.end(); + client.release(); return confirmedToken; } diff --git a/actions/get_phone_rsvp_to_event_state.ts b/actions/get_phone_rsvp_to_event_state.ts index 225f5a1f..3f96c37f 100644 --- a/actions/get_phone_rsvp_to_event_state.ts +++ b/actions/get_phone_rsvp_to_event_state.ts @@ -1,6 +1,6 @@ "use server"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { and, eq } from "drizzle-orm"; import postgres from "postgres"; import { @@ -9,6 +9,7 @@ import { } from "drizzle/schema"; import { cookies } from "next/headers"; import { Database } from "supabase/database.types"; +import { pool } from "supabase/pool"; export async function getPhoneRSVPToEventState(entityId: string) { const token = (await cookies()).get("phone_auth_token"); @@ -17,7 +18,7 @@ export async function getPhoneRSVPToEventState(entityId: string) { return null; } - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); const [authToken] = await db @@ -26,7 +27,7 @@ export async function getPhoneRSVPToEventState(entityId: string) { .where(eq(phone_number_auth_tokens.id, token.value)); if (!authToken || !authToken.confirmed) { - client.end(); + client.release(); return null; } @@ -40,6 +41,6 @@ export async function getPhoneRSVPToEventState(entityId: string) { ), ); - client.end(); + client.release(); return rsvp; } diff --git a/actions/login.ts b/actions/login.ts index d2208e69..b19a3a91 100644 --- a/actions/login.ts +++ b/actions/login.ts @@ -1,5 +1,5 @@ "use server"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import postgres from "postgres"; import { email_auth_tokens, @@ -16,11 +16,12 @@ import { cookies } from "next/headers"; import { redirect } from "next/navigation"; import { v7 } from "uuid"; import { createIdentity } from "./createIdentity"; +import { pool } from "supabase/pool"; export async function loginWithEmailToken( localLeaflets: { token: { id: string }; added_at: string }[], ) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); let token_id = (await cookies()).get("auth_token")?.value; let voter_token = (await cookies()).get("poll_voter_token")?.value; @@ -115,5 +116,5 @@ export async function loginWithEmailToken( }); } } - client.end(); + client.release(); } diff --git a/actions/phone_auth/confirm_phone_auth_token.ts b/actions/phone_auth/confirm_phone_auth_token.ts index 5f08d8a7..21a42816 100644 --- a/actions/phone_auth/confirm_phone_auth_token.ts +++ b/actions/phone_auth/confirm_phone_auth_token.ts @@ -1,13 +1,14 @@ "use server"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { and, eq } from "drizzle-orm"; import postgres from "postgres"; import { phone_number_auth_tokens } from "drizzle/schema"; import { cookies } from "next/headers"; +import { pool } from "supabase/pool"; export async function confirmPhoneAuthToken(tokenId: string, code: string) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); const [token] = await db @@ -16,17 +17,17 @@ export async function confirmPhoneAuthToken(tokenId: string, code: string) { .where(eq(phone_number_auth_tokens.id, tokenId)); if (!token) { - client.end(); + client.release(); throw new Error("Invalid token"); } if (token.confirmation_code !== code) { - client.end(); + client.release(); throw new Error("Invalid confirmation code"); } if (token.confirmed) { - client.end(); + client.release(); throw new Error("Token already confirmed"); } @@ -50,6 +51,6 @@ export async function confirmPhoneAuthToken(tokenId: string, code: string) { sameSite: "strict", }); - client.end(); + client.release(); return confirmedToken; } diff --git a/actions/phone_auth/request_phone_auth_token.ts b/actions/phone_auth/request_phone_auth_token.ts index a777dfc9..49ccc33b 100644 --- a/actions/phone_auth/request_phone_auth_token.ts +++ b/actions/phone_auth/request_phone_auth_token.ts @@ -1,10 +1,11 @@ "use server"; import { randomBytes } from "crypto"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import postgres from "postgres"; import { phone_number_auth_tokens } from "drizzle/schema"; import twilio from "twilio"; +import { pool } from "supabase/pool"; async function sendAuthCode({ country_code, @@ -46,7 +47,7 @@ export async function createPhoneAuthToken({ phone_number: string; country_code: string; }) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); const code = randomBytes(3).toString("hex").toUpperCase(); @@ -65,6 +66,6 @@ export async function createPhoneAuthToken({ await sendAuthCode({ country_code, phone_number, code }); - client.end(); + client.release(); return token.id; } diff --git a/actions/phone_rsvp_to_event.ts b/actions/phone_rsvp_to_event.ts index 1cedae3f..17d6e2bd 100644 --- a/actions/phone_rsvp_to_event.ts +++ b/actions/phone_rsvp_to_event.ts @@ -1,6 +1,6 @@ "use server"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { entities, phone_number_auth_tokens, @@ -13,6 +13,7 @@ import { eq, sql } from "drizzle-orm"; import { Database } from "supabase/database.types"; import { createServerClient } from "@supabase/ssr"; import { cookies } from "next/headers"; +import { pool } from "supabase/pool"; export async function submitRSVP(args: { entity: string; @@ -20,7 +21,7 @@ export async function submitRSVP(args: { name: string; plus_ones: number; }) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); let token = (await cookies()).get("phone_auth_token"); if (!token) throw new Error("No auth token found"); @@ -58,6 +59,6 @@ export async function submitRSVP(args: { }); }); - client.end(); + client.release(); return { success: true }; } diff --git a/actions/removeLeafletFromHome.ts b/actions/removeLeafletFromHome.ts index 56e2fa4a..0c1a9321 100644 --- a/actions/removeLeafletFromHome.ts +++ b/actions/removeLeafletFromHome.ts @@ -1,18 +1,19 @@ "use server"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { permission_token_on_homepage } from "drizzle/schema"; import postgres from "postgres"; import { v7 } from "uuid"; import { sql, eq, inArray, and } from "drizzle-orm"; import { cookies } from "next/headers"; import { getIdentityData } from "./getIdentityData"; +import { pool } from "supabase/pool"; export async function removeLeafletFromHome(tokens: string[]) { const identity = await getIdentityData(); if (!identity) return null; - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); await db @@ -24,6 +25,6 @@ export async function removeLeafletFromHome(tokens: string[]) { ), ); - client.end(); + client.release(); return true; } diff --git a/actions/sendUpdateToRSVPS.ts b/actions/sendUpdateToRSVPS.ts index 443be9f6..2b1d429b 100644 --- a/actions/sendUpdateToRSVPS.ts +++ b/actions/sendUpdateToRSVPS.ts @@ -1,22 +1,13 @@ "use server"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { eq } from "drizzle-orm"; -import postgres from "postgres"; import { entities, permission_token_rights, phone_rsvps_to_entity, } from "drizzle/schema"; -import { createClient } from "@supabase/supabase-js"; -import { Database } from "supabase/database.types"; import twilio from "twilio"; - -const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); -let supabase = createClient( - process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, - process.env.SUPABASE_SERVICE_ROLE_KEY as string, -); -const db = drizzle(client); +import { pool } from "supabase/pool"; export async function sendUpdateToRSVPS( token: { id: string }, @@ -34,6 +25,8 @@ export async function sendUpdateToRSVPS( sendto: { GOING: boolean; MAYBE: boolean; NOT_GOING: boolean }; }, ) { + let dbclient = await pool.connect(); + const db = drizzle(dbclient); let token_rights = await db .select() .from(permission_token_rights) @@ -45,6 +38,8 @@ export async function sendUpdateToRSVPS( .innerJoin(entities, eq(phone_rsvps_to_entity.entity, entities.id)) .where(eq(phone_rsvps_to_entity.entity, entity)); + dbclient.release(); + if (!token_rights[0]?.write) return; let rsvps = await RSVPS; let entity_set = rsvps[0]?.entities.set; diff --git a/actions/subscriptions/confirmEmailSubscription.ts b/actions/subscriptions/confirmEmailSubscription.ts index 0d54cba9..f450b01b 100644 --- a/actions/subscriptions/confirmEmailSubscription.ts +++ b/actions/subscriptions/confirmEmailSubscription.ts @@ -2,7 +2,7 @@ import { createClient } from "@supabase/supabase-js"; import { and, eq, sql } from "drizzle-orm"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { email_subscriptions_to_entity, facts, @@ -11,13 +11,14 @@ import { import postgres from "postgres"; import type { Fact } from "src/replicache"; import { Database } from "supabase/database.types"; +import { pool } from "supabase/pool"; import { v7 } from "uuid"; export async function confirmEmailSubscription( subscriptionID: string, code: string, ) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); let subscription = await db.transaction(async (tx) => { let [{ email_subscriptions_to_entity: sub, permission_tokens: token }] = @@ -80,6 +81,6 @@ export async function confirmEmailSubscription( payload: { message: "poke" }, }); supabase.removeChannel(channel); - client.end(); + client.release(); return subscription; } diff --git a/actions/subscriptions/deleteSubscription.ts b/actions/subscriptions/deleteSubscription.ts index 8350434c..5199e2ac 100644 --- a/actions/subscriptions/deleteSubscription.ts +++ b/actions/subscriptions/deleteSubscription.ts @@ -1,14 +1,15 @@ "use server"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { email_subscriptions_to_entity, facts } from "drizzle/schema"; import postgres from "postgres"; import { eq, and, sql } from "drizzle-orm"; import type { Fact } from "src/replicache"; import { v7 } from "uuid"; +import { pool } from "supabase/pool"; export async function deleteSubscription(subscriptionID: string) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); try { @@ -41,11 +42,11 @@ export async function deleteSubscription(subscriptionID: string) { .where(eq(email_subscriptions_to_entity.id, subscriptionID)); }); - client.end(); + client.release(); return { success: true }; } catch (error) { console.error("Error unsubscribing:", error); - client.end(); + client.release(); return { success: false, error: "Failed to unsubscribe" }; } } diff --git a/actions/subscriptions/sendPostToSubscribers.ts b/actions/subscriptions/sendPostToSubscribers.ts index 8aeeee76..6b590f19 100644 --- a/actions/subscriptions/sendPostToSubscribers.ts +++ b/actions/subscriptions/sendPostToSubscribers.ts @@ -3,11 +3,12 @@ import { getCurrentDeploymentDomain } from "src/utils/getCurrentDeploymentDomain"; import { createServerClient } from "@supabase/ssr"; import { and, eq } from "drizzle-orm"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { email_subscriptions_to_entity, entities } from "drizzle/schema"; import postgres from "postgres"; import type { PermissionToken } from "src/replicache"; import { Database } from "supabase/database.types"; +import { pool } from "supabase/pool"; let supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, @@ -41,7 +42,7 @@ export async function sendPostToSubscribers({ root: rootEntity, }); - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); let subscribers = await db .select() @@ -95,6 +96,6 @@ export async function sendPostToSubscribers({ })), ), }); - client.end(); + client.release(); return; } diff --git a/actions/subscriptions/subscribeToMailboxWithEmail.ts b/actions/subscriptions/subscribeToMailboxWithEmail.ts index 6710b26c..08a65cec 100644 --- a/actions/subscriptions/subscribeToMailboxWithEmail.ts +++ b/actions/subscriptions/subscribeToMailboxWithEmail.ts @@ -3,7 +3,7 @@ import * as base64 from "base64-js"; import { createServerClient } from "@supabase/ssr"; import { and, eq } from "drizzle-orm"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { email_subscriptions_to_entity } from "drizzle/schema"; import postgres from "postgres"; import { getBlocksWithTypeLocal } from "src/hooks/queries/useBlocks"; @@ -12,6 +12,7 @@ import type { Attribute } from "src/replicache/attributes"; import { Database } from "supabase/database.types"; import * as Y from "yjs"; import { YJSFragmentToString } from "components/Blocks/TextBlock/RenderYJSFragment"; +import { pool } from "supabase/pool"; let supabase = createServerClient( process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, @@ -37,7 +38,7 @@ export async function subscribeToMailboxWithEmail( email: string, token: PermissionToken, ) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); let newCode = generateCode(); let subscription = await db.transaction(async (tx) => { @@ -82,7 +83,7 @@ ${subscription.confirmation_code} `, }), }); - client.end(); + client.release(); return subscription; } diff --git a/app/api/oauth/[route]/route.ts b/app/api/oauth/[route]/route.ts index dfe328b7..b335015c 100644 --- a/app/api/oauth/[route]/route.ts +++ b/app/api/oauth/[route]/route.ts @@ -1,10 +1,9 @@ import { createIdentity } from "actions/createIdentity"; import { subscribeToPublication } from "app/lish/subscribeToPublication"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { cookies } from "next/headers"; import { redirect } from "next/navigation"; import { NextRequest, NextResponse } from "next/server"; -import postgres from "postgres"; import { createOauthClient } from "src/atproto-oauth"; import { setAuthToken } from "src/auth"; @@ -14,6 +13,7 @@ import { ActionAfterSignIn, parseActionFromSearchParam, } from "./afterSignInActions"; +import { pool } from "supabase/pool"; type OauthRequestClientState = { redirect: string | null; @@ -81,11 +81,10 @@ export async function GET( return handleAction(s.action, redirectPath); } - const client = postgres(process.env.DB_URL as string, { - idle_timeout: 5, - }); + const client = await pool.connect(); const db = drizzle(client); identity = await createIdentity(db, { atp_did: session.did }); + client.release(); } let { data: token } = await supabaseServerClient .from("email_auth_tokens") diff --git a/app/api/rpc/[command]/route.ts b/app/api/rpc/[command]/route.ts index 1734fcbc..c6627540 100644 --- a/app/api/rpc/[command]/route.ts +++ b/app/api/rpc/[command]/route.ts @@ -1,7 +1,5 @@ -import { drizzle } from "drizzle-orm/postgres-js"; import { makeRouter } from "../lib"; import { push } from "./push"; -import postgres from "postgres"; import { createClient } from "@supabase/supabase-js"; import { Database } from "supabase/database.types"; import { pull } from "./pull"; diff --git a/app/emails/unsubscribe/route.ts b/app/emails/unsubscribe/route.ts index dc01c7bd..8f3adace 100644 --- a/app/emails/unsubscribe/route.ts +++ b/app/emails/unsubscribe/route.ts @@ -1,13 +1,14 @@ import { NextRequest } from "next/server"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { email_subscriptions_to_entity } from "drizzle/schema"; import postgres from "postgres"; import { eq } from "drizzle-orm"; +import { pool } from "supabase/pool"; export async function POST(request: NextRequest) { let sub_id = request.nextUrl.searchParams.get("sub_id"); if (!sub_id) return new Response(null, { status: 404 }); - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); try { @@ -17,6 +18,6 @@ export async function POST(request: NextRequest) { } catch (error) { console.log(error); } - client.end(); + client.release(); return new Response(null, { status: 200 }); } diff --git a/app/home/page.tsx b/app/home/page.tsx index ed286634..45ffd500 100644 --- a/app/home/page.tsx +++ b/app/home/page.tsx @@ -7,8 +7,7 @@ import { } from "components/ThemeManager/ThemeProvider"; import { EntitySetProvider } from "components/EntitySetProvider"; import { createIdentity } from "actions/createIdentity"; -import postgres from "postgres"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { IdentitySetter } from "./IdentitySetter"; import { LeafletList } from "./LeafletList"; import { getIdentityData } from "actions/getIdentityData"; @@ -18,6 +17,7 @@ import { HomeFooter } from "./HomeFooter"; import { Media } from "components/Media"; import { MyPublicationList } from "./Publications"; import { supabaseServerClient } from "supabase/serverClient"; +import { pool } from "supabase/pool"; export default async function Home() { let cookieStore = await cookies(); @@ -27,10 +27,10 @@ export default async function Home() { else identity = cookieStore.get("identity")?.value; let needstosetcookie = false; if (!identity) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); let newIdentity = await createIdentity(db); - client.end(); + client.release(); identity = newIdentity.id; needstosetcookie = true; } diff --git a/appview/index.ts b/appview/index.ts index 72f18446..3c5f94e3 100644 --- a/appview/index.ts +++ b/appview/index.ts @@ -18,9 +18,9 @@ import { import { AtUri } from "@atproto/syntax"; import { writeFile, readFile } from "fs/promises"; import { createIdentity } from "actions/createIdentity"; -import postgres from "postgres"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { inngest } from "app/api/inngest/client"; +import { pool } from "supabase/pool"; const cursorFile = process.env.CURSOR_FILE || "/cursor/cursor"; @@ -35,7 +35,7 @@ async function main() { startCursor = parseInt((await readFile(cursorFile)).toString()); } catch (e) {} - const client = postgres(process.env.DB_URL!); + const client = await pool.connect(); const db = drizzle(client); async function handleEvent(evt: Event) { if (evt.event === "identity") { @@ -257,7 +257,7 @@ async function main() { firehose.start(); const cleanup = async () => { console.log("shutting down firehose..."); - await client.end(); + await client.release(); await firehose.destroy(); await runner.destroy(); process.exit(); diff --git a/components/ShareOptions/getShareLink.ts b/components/ShareOptions/getShareLink.ts index 12f8fca5..618a2aaa 100644 --- a/components/ShareOptions/getShareLink.ts +++ b/components/ShareOptions/getShareLink.ts @@ -1,14 +1,14 @@ "use server"; import { eq, and } from "drizzle-orm"; -import { drizzle } from "drizzle-orm/postgres-js"; +import { drizzle } from "drizzle-orm/node-postgres"; import { permission_token_rights, permission_tokens } from "drizzle/schema"; -import postgres from "postgres"; +import { pool } from "supabase/pool"; export async function getShareLink( token: { id: string; entity_set: string }, rootEntity: string, ) { - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); + const client = await pool.connect(); const db = drizzle(client); let link = await db.transaction(async (tx) => { // This will likely error out when if we have multiple permission @@ -65,6 +65,6 @@ export async function getShareLink( return newToken; }); - client.end(); + client.release(); return link; } diff --git a/package-lock.json b/package-lock.json index 2ea0a30c..d38c63ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,6 @@ "multiformats": "^13.3.2", "next": "^15.5.0", "pg": "^8.16.3", - "postgres": "^3.4.4", "prosemirror-commands": "^1.5.2", "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", @@ -14109,6 +14108,8 @@ "version": "3.4.4", "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.4.tgz", "integrity": "sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==", + "optional": true, + "peer": true, "engines": { "node": ">=12" }, diff --git a/package.json b/package.json index fe6f8f1e..abb7f840 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,6 @@ "multiformats": "^13.3.2", "next": "^15.5.0", "pg": "^8.16.3", - "postgres": "^3.4.4", "prosemirror-commands": "^1.5.2", "prosemirror-inputrules": "^1.4.0", "prosemirror-keymap": "^1.2.2", diff --git a/supabase/pool.ts b/supabase/pool.ts new file mode 100644 index 00000000..2ba68c26 --- /dev/null +++ b/supabase/pool.ts @@ -0,0 +1,12 @@ +import { Pool } from "pg"; +import { attachDatabasePool } from "@vercel/functions"; +import { DbPool } from "@vercel/functions/db-connections"; + +export const pool = new Pool({ + idleTimeoutMillis: 5000, + min: 1, + connectionString: process.env.DB_URL, +}); + +// Attach the pool to ensure idle connections close before suspension +attachDatabasePool(pool as DbPool);