a tool for shared writing and social publishing

use node-postgres and vercel's attachDBPool everywhere

+117 -121
+5 -18
actions/addLeafletToHome.ts
··· 1 1 "use server"; 2 2 3 - import { drizzle } from "drizzle-orm/postgres-js"; 4 - import { 5 - entities, 6 - identities, 7 - permission_tokens, 8 - permission_token_rights, 9 - entity_sets, 10 - facts, 11 - permission_token_on_homepage, 12 - email_auth_tokens, 13 - } from "drizzle/schema"; 14 - import { redirect } from "next/navigation"; 15 - import postgres from "postgres"; 16 - import { v7 } from "uuid"; 17 - import { sql, eq, and } from "drizzle-orm"; 3 + import { drizzle } from "drizzle-orm/node-postgres"; 4 + import { sql } from "drizzle-orm"; 18 5 import { cookies } from "next/headers"; 6 + import { pool } from "supabase/pool"; 19 7 20 8 export async function addLeafletToHome(leaflet: string) { 21 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 22 9 let auth_token = (await cookies()).get("auth_token")?.value; 10 + const client = await pool.connect(); 23 11 const db = drizzle(client); 24 12 await db.transaction(async (tx) => { 25 13 if (auth_token) { ··· 40 28 41 29 return; 42 30 }); 43 - 44 - client.end(); 31 + client.release(); 45 32 return; 46 33 }
+4 -7
actions/createIdentity.ts
··· 1 - import { PostgresJsDatabase } from "drizzle-orm/postgres-js"; 2 1 import { 3 2 entities, 4 3 permission_tokens, 5 4 permission_token_rights, 6 5 entity_sets, 7 - facts, 8 6 identities, 9 7 } from "drizzle/schema"; 10 - import { redirect } from "next/navigation"; 11 - import postgres from "postgres"; 12 8 import { v7 } from "uuid"; 13 - import { sql } from "drizzle-orm"; 14 - import { cookies } from "next/headers"; 9 + import { PgTransaction } from "drizzle-orm/pg-core"; 10 + import { NodePgDatabase } from "drizzle-orm/node-postgres"; 11 + 15 12 export async function createIdentity( 16 - db: PostgresJsDatabase, 13 + db: NodePgDatabase, 17 14 data?: { email?: string; atp_did?: string }, 18 15 ) { 19 16 return db.transaction(async (tx) => {
+4 -3
actions/createNewLeaflet.ts
··· 1 1 "use server"; 2 2 3 - import { drizzle } from "drizzle-orm/postgres-js"; 3 + import { drizzle } from "drizzle-orm/node-postgres"; 4 4 import { 5 5 entities, 6 6 identities, ··· 16 16 import { v7 } from "uuid"; 17 17 import { sql, eq, and } from "drizzle-orm"; 18 18 import { cookies } from "next/headers"; 19 + import { pool } from "supabase/pool"; 19 20 20 21 export async function createNewLeaflet({ 21 22 pageType, ··· 26 27 redirectUser: boolean; 27 28 firstBlockType?: "h1" | "text"; 28 29 }) { 29 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 30 30 let auth_token = (await cookies()).get("auth_token")?.value; 31 + const client = await pool.connect(); 31 32 const db = drizzle(client); 32 33 let { permissionToken } = await db.transaction(async (tx) => { 33 34 // Create a new entity set ··· 156 157 return { permissionToken, rights, root_entity, entity_set }; 157 158 }); 158 159 159 - client.end(); 160 + client.release(); 160 161 if (redirectUser) redirect(`/${permissionToken.id}?focusFirstBlock`); 161 162 return permissionToken.id; 162 163 }
+4 -5
actions/createNewLeafletFromTemplate.ts
··· 1 1 "use server"; 2 2 3 3 import { createServerClient } from "@supabase/ssr"; 4 - import { drizzle } from "drizzle-orm/postgres-js"; 5 - import { NextRequest } from "next/server"; 6 - import postgres from "postgres"; 4 + import { drizzle } from "drizzle-orm/node-postgres"; 7 5 import type { Fact } from "src/replicache"; 8 6 import type { Attribute } from "src/replicache/attributes"; 9 7 import { Database } from "supabase/database.types"; ··· 19 17 import { sql } from "drizzle-orm"; 20 18 import { redirect } from "next/navigation"; 21 19 import { cookies } from "next/headers"; 20 + import { pool } from "supabase/pool"; 22 21 23 22 let supabase = createServerClient<Database>( 24 23 process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, ··· 84 83 }), 85 84 ); 86 85 87 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 86 + const client = await pool.connect(); 88 87 const db = drizzle(client); 89 88 90 89 let { permissionToken } = await db.transaction(async (tx) => { ··· 138 137 return { permissionToken, rights, entity_set }; 139 138 }); 140 139 141 - client.end(); 140 + client.release(); 142 141 if (redirectUser) redirect(`/${permissionToken.id}`); 143 142 return { id: permissionToken.id, error: null } as const; 144 143 }
+5 -9
actions/deleteLeaflet.ts
··· 1 1 "use server"; 2 2 3 - import { drizzle } from "drizzle-orm/postgres-js"; 3 + import { drizzle } from "drizzle-orm/node-postgres"; 4 4 import { 5 5 entities, 6 6 permission_tokens, 7 7 permission_token_rights, 8 8 } from "drizzle/schema"; 9 - import { redirect } from "next/navigation"; 10 - import postgres from "postgres"; 11 - import { v7 } from "uuid"; 12 - import { eq, sql } from "drizzle-orm"; 13 - import { cookies } from "next/headers"; 9 + import { eq } from "drizzle-orm"; 14 10 import { PermissionToken } from "src/replicache"; 15 - import { revalidatePath } from "next/cache"; 11 + import { pool } from "supabase/pool"; 16 12 17 13 export async function deleteLeaflet(permission_token: PermissionToken) { 18 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 14 + const client = await pool.connect(); 19 15 const db = drizzle(client); 20 16 await db.transaction(async (tx) => { 21 17 let [token] = await tx ··· 35 31 .delete(permission_tokens) 36 32 .where(eq(permission_tokens.id, permission_token.id)); 37 33 }); 38 - client.end(); 34 + client.release(); 39 35 return; 40 36 }
+10 -9
actions/emailAuth.ts
··· 1 1 "use server"; 2 2 3 3 import { randomBytes } from "crypto"; 4 - import { drizzle } from "drizzle-orm/postgres-js"; 4 + import { drizzle } from "drizzle-orm/node-postgres"; 5 5 import postgres from "postgres"; 6 6 import { email_auth_tokens, identities } from "drizzle/schema"; 7 7 import { and, eq } from "drizzle-orm"; 8 8 import { cookies } from "next/headers"; 9 9 import { createIdentity } from "./createIdentity"; 10 10 import { setAuthToken } from "src/auth"; 11 + import { pool } from "supabase/pool"; 11 12 12 13 async function sendAuthCode(email: string, code: string) { 13 14 if (process.env.NODE_ENV === "development") { ··· 42 43 43 44 export async function requestAuthEmailToken(emailNonNormalized: string) { 44 45 let email = emailNonNormalized.toLowerCase(); 45 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 46 + const client = await pool.connect(); 46 47 const db = drizzle(client); 47 48 48 49 const code = randomBytes(3).toString("hex").toUpperCase(); ··· 60 61 61 62 await sendAuthCode(email, code); 62 63 63 - client.end(); 64 + client.release(); 64 65 return token.id; 65 66 } 66 67 67 68 export async function confirmEmailAuthToken(tokenId: string, code: string) { 68 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 69 + const client = await pool.connect(); 69 70 const db = drizzle(client); 70 71 71 72 const [token] = await db ··· 74 75 .where(eq(email_auth_tokens.id, tokenId)); 75 76 76 77 if (!token || !token.email) { 77 - client.end(); 78 + client.release(); 78 79 return null; 79 80 } 80 81 81 82 if (token.confirmation_code !== code) { 82 - client.end(); 83 + client.release(); 83 84 return null; 84 85 } 85 86 86 87 if (token.confirmed) { 87 - client.end(); 88 + client.release(); 88 89 return null; 89 90 } 90 91 let authToken = (await cookies()).get("auth_token"); ··· 102 103 .update(identities) 103 104 .set({ email: token.email }) 104 105 .where(eq(identities.id, existingToken.identities.id)); 105 - client.end(); 106 + client.release(); 106 107 return existingToken; 107 108 } 108 109 } ··· 135 136 136 137 await setAuthToken(confirmedToken.id); 137 138 138 - client.end(); 139 + client.release(); 139 140 return confirmedToken; 140 141 }
+5 -4
actions/get_phone_rsvp_to_event_state.ts
··· 1 1 "use server"; 2 2 3 - import { drizzle } from "drizzle-orm/postgres-js"; 3 + import { drizzle } from "drizzle-orm/node-postgres"; 4 4 import { and, eq } from "drizzle-orm"; 5 5 import postgres from "postgres"; 6 6 import { ··· 9 9 } from "drizzle/schema"; 10 10 import { cookies } from "next/headers"; 11 11 import { Database } from "supabase/database.types"; 12 + import { pool } from "supabase/pool"; 12 13 13 14 export async function getPhoneRSVPToEventState(entityId: string) { 14 15 const token = (await cookies()).get("phone_auth_token"); ··· 17 18 return null; 18 19 } 19 20 20 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 21 + const client = await pool.connect(); 21 22 const db = drizzle(client); 22 23 23 24 const [authToken] = await db ··· 26 27 .where(eq(phone_number_auth_tokens.id, token.value)); 27 28 28 29 if (!authToken || !authToken.confirmed) { 29 - client.end(); 30 + client.release(); 30 31 return null; 31 32 } 32 33 ··· 40 41 ), 41 42 ); 42 43 43 - client.end(); 44 + client.release(); 44 45 return rsvp; 45 46 }
+4 -3
actions/login.ts
··· 1 1 "use server"; 2 - import { drizzle } from "drizzle-orm/postgres-js"; 2 + import { drizzle } from "drizzle-orm/node-postgres"; 3 3 import postgres from "postgres"; 4 4 import { 5 5 email_auth_tokens, ··· 16 16 import { redirect } from "next/navigation"; 17 17 import { v7 } from "uuid"; 18 18 import { createIdentity } from "./createIdentity"; 19 + import { pool } from "supabase/pool"; 19 20 20 21 export async function loginWithEmailToken( 21 22 localLeaflets: { token: { id: string }; added_at: string }[], 22 23 ) { 23 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 24 + const client = await pool.connect(); 24 25 const db = drizzle(client); 25 26 let token_id = (await cookies()).get("auth_token")?.value; 26 27 let voter_token = (await cookies()).get("poll_voter_token")?.value; ··· 115 116 }); 116 117 } 117 118 } 118 - client.end(); 119 + client.release(); 119 120 }
+7 -6
actions/phone_auth/confirm_phone_auth_token.ts
··· 1 1 "use server"; 2 2 3 - import { drizzle } from "drizzle-orm/postgres-js"; 3 + import { drizzle } from "drizzle-orm/node-postgres"; 4 4 import { and, eq } from "drizzle-orm"; 5 5 import postgres from "postgres"; 6 6 import { phone_number_auth_tokens } from "drizzle/schema"; 7 7 import { cookies } from "next/headers"; 8 + import { pool } from "supabase/pool"; 8 9 9 10 export async function confirmPhoneAuthToken(tokenId: string, code: string) { 10 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 11 + const client = await pool.connect(); 11 12 const db = drizzle(client); 12 13 13 14 const [token] = await db ··· 16 17 .where(eq(phone_number_auth_tokens.id, tokenId)); 17 18 18 19 if (!token) { 19 - client.end(); 20 + client.release(); 20 21 throw new Error("Invalid token"); 21 22 } 22 23 23 24 if (token.confirmation_code !== code) { 24 - client.end(); 25 + client.release(); 25 26 throw new Error("Invalid confirmation code"); 26 27 } 27 28 28 29 if (token.confirmed) { 29 - client.end(); 30 + client.release(); 30 31 throw new Error("Token already confirmed"); 31 32 } 32 33 ··· 50 51 sameSite: "strict", 51 52 }); 52 53 53 - client.end(); 54 + client.release(); 54 55 return confirmedToken; 55 56 }
+4 -3
actions/phone_auth/request_phone_auth_token.ts
··· 1 1 "use server"; 2 2 3 3 import { randomBytes } from "crypto"; 4 - import { drizzle } from "drizzle-orm/postgres-js"; 4 + import { drizzle } from "drizzle-orm/node-postgres"; 5 5 import postgres from "postgres"; 6 6 import { phone_number_auth_tokens } from "drizzle/schema"; 7 7 import twilio from "twilio"; 8 + import { pool } from "supabase/pool"; 8 9 9 10 async function sendAuthCode({ 10 11 country_code, ··· 46 47 phone_number: string; 47 48 country_code: string; 48 49 }) { 49 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 50 + const client = await pool.connect(); 50 51 const db = drizzle(client); 51 52 52 53 const code = randomBytes(3).toString("hex").toUpperCase(); ··· 65 66 66 67 await sendAuthCode({ country_code, phone_number, code }); 67 68 68 - client.end(); 69 + client.release(); 69 70 return token.id; 70 71 }
+4 -3
actions/phone_rsvp_to_event.ts
··· 1 1 "use server"; 2 2 3 - import { drizzle } from "drizzle-orm/postgres-js"; 3 + import { drizzle } from "drizzle-orm/node-postgres"; 4 4 import { 5 5 entities, 6 6 phone_number_auth_tokens, ··· 13 13 import { Database } from "supabase/database.types"; 14 14 import { createServerClient } from "@supabase/ssr"; 15 15 import { cookies } from "next/headers"; 16 + import { pool } from "supabase/pool"; 16 17 17 18 export async function submitRSVP(args: { 18 19 entity: string; ··· 20 21 name: string; 21 22 plus_ones: number; 22 23 }) { 23 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 24 + const client = await pool.connect(); 24 25 const db = drizzle(client); 25 26 let token = (await cookies()).get("phone_auth_token"); 26 27 if (!token) throw new Error("No auth token found"); ··· 58 59 }); 59 60 }); 60 61 61 - client.end(); 62 + client.release(); 62 63 return { success: true }; 63 64 }
+4 -3
actions/removeLeafletFromHome.ts
··· 1 1 "use server"; 2 2 3 - import { drizzle } from "drizzle-orm/postgres-js"; 3 + import { drizzle } from "drizzle-orm/node-postgres"; 4 4 import { permission_token_on_homepage } from "drizzle/schema"; 5 5 import postgres from "postgres"; 6 6 import { v7 } from "uuid"; 7 7 import { sql, eq, inArray, and } from "drizzle-orm"; 8 8 import { cookies } from "next/headers"; 9 9 import { getIdentityData } from "./getIdentityData"; 10 + import { pool } from "supabase/pool"; 10 11 11 12 export async function removeLeafletFromHome(tokens: string[]) { 12 13 const identity = await getIdentityData(); 13 14 if (!identity) return null; 14 15 15 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 16 + const client = await pool.connect(); 16 17 const db = drizzle(client); 17 18 18 19 await db ··· 24 25 ), 25 26 ); 26 27 27 - client.end(); 28 + client.release(); 28 29 return true; 29 30 }
+6 -11
actions/sendUpdateToRSVPS.ts
··· 1 1 "use server"; 2 - import { drizzle } from "drizzle-orm/postgres-js"; 2 + import { drizzle } from "drizzle-orm/node-postgres"; 3 3 import { eq } from "drizzle-orm"; 4 - import postgres from "postgres"; 5 4 import { 6 5 entities, 7 6 permission_token_rights, 8 7 phone_rsvps_to_entity, 9 8 } from "drizzle/schema"; 10 - import { createClient } from "@supabase/supabase-js"; 11 - import { Database } from "supabase/database.types"; 12 9 import twilio from "twilio"; 13 - 14 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 15 - let supabase = createClient<Database>( 16 - process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, 17 - process.env.SUPABASE_SERVICE_ROLE_KEY as string, 18 - ); 19 - const db = drizzle(client); 10 + import { pool } from "supabase/pool"; 20 11 21 12 export async function sendUpdateToRSVPS( 22 13 token: { id: string }, ··· 34 25 sendto: { GOING: boolean; MAYBE: boolean; NOT_GOING: boolean }; 35 26 }, 36 27 ) { 28 + let dbclient = await pool.connect(); 29 + const db = drizzle(dbclient); 37 30 let token_rights = await db 38 31 .select() 39 32 .from(permission_token_rights) ··· 44 37 .from(phone_rsvps_to_entity) 45 38 .innerJoin(entities, eq(phone_rsvps_to_entity.entity, entities.id)) 46 39 .where(eq(phone_rsvps_to_entity.entity, entity)); 40 + 41 + dbclient.release(); 47 42 48 43 if (!token_rights[0]?.write) return; 49 44 let rsvps = await RSVPS;
+4 -3
actions/subscriptions/confirmEmailSubscription.ts
··· 2 2 3 3 import { createClient } from "@supabase/supabase-js"; 4 4 import { and, eq, sql } from "drizzle-orm"; 5 - import { drizzle } from "drizzle-orm/postgres-js"; 5 + import { drizzle } from "drizzle-orm/node-postgres"; 6 6 import { 7 7 email_subscriptions_to_entity, 8 8 facts, ··· 11 11 import postgres from "postgres"; 12 12 import type { Fact } from "src/replicache"; 13 13 import { Database } from "supabase/database.types"; 14 + import { pool } from "supabase/pool"; 14 15 import { v7 } from "uuid"; 15 16 16 17 export async function confirmEmailSubscription( 17 18 subscriptionID: string, 18 19 code: string, 19 20 ) { 20 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 21 + const client = await pool.connect(); 21 22 const db = drizzle(client); 22 23 let subscription = await db.transaction(async (tx) => { 23 24 let [{ email_subscriptions_to_entity: sub, permission_tokens: token }] = ··· 80 81 payload: { message: "poke" }, 81 82 }); 82 83 supabase.removeChannel(channel); 83 - client.end(); 84 + client.release(); 84 85 return subscription; 85 86 }
+5 -4
actions/subscriptions/deleteSubscription.ts
··· 1 1 "use server"; 2 2 3 - import { drizzle } from "drizzle-orm/postgres-js"; 3 + import { drizzle } from "drizzle-orm/node-postgres"; 4 4 import { email_subscriptions_to_entity, facts } from "drizzle/schema"; 5 5 import postgres from "postgres"; 6 6 import { eq, and, sql } from "drizzle-orm"; 7 7 import type { Fact } from "src/replicache"; 8 8 import { v7 } from "uuid"; 9 + import { pool } from "supabase/pool"; 9 10 10 11 export async function deleteSubscription(subscriptionID: string) { 11 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 12 + const client = await pool.connect(); 12 13 const db = drizzle(client); 13 14 14 15 try { ··· 41 42 .where(eq(email_subscriptions_to_entity.id, subscriptionID)); 42 43 }); 43 44 44 - client.end(); 45 + client.release(); 45 46 return { success: true }; 46 47 } catch (error) { 47 48 console.error("Error unsubscribing:", error); 48 - client.end(); 49 + client.release(); 49 50 return { success: false, error: "Failed to unsubscribe" }; 50 51 } 51 52 }
+4 -3
actions/subscriptions/sendPostToSubscribers.ts
··· 3 3 import { getCurrentDeploymentDomain } from "src/utils/getCurrentDeploymentDomain"; 4 4 import { createServerClient } from "@supabase/ssr"; 5 5 import { and, eq } from "drizzle-orm"; 6 - import { drizzle } from "drizzle-orm/postgres-js"; 6 + import { drizzle } from "drizzle-orm/node-postgres"; 7 7 import { email_subscriptions_to_entity, entities } from "drizzle/schema"; 8 8 import postgres from "postgres"; 9 9 import type { PermissionToken } from "src/replicache"; 10 10 import { Database } from "supabase/database.types"; 11 + import { pool } from "supabase/pool"; 11 12 12 13 let supabase = createServerClient<Database>( 13 14 process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, ··· 41 42 root: rootEntity, 42 43 }); 43 44 44 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 45 + const client = await pool.connect(); 45 46 const db = drizzle(client); 46 47 let subscribers = await db 47 48 .select() ··· 95 96 })), 96 97 ), 97 98 }); 98 - client.end(); 99 + client.release(); 99 100 return; 100 101 }
+4 -3
actions/subscriptions/subscribeToMailboxWithEmail.ts
··· 3 3 import * as base64 from "base64-js"; 4 4 import { createServerClient } from "@supabase/ssr"; 5 5 import { and, eq } from "drizzle-orm"; 6 - import { drizzle } from "drizzle-orm/postgres-js"; 6 + import { drizzle } from "drizzle-orm/node-postgres"; 7 7 import { email_subscriptions_to_entity } from "drizzle/schema"; 8 8 import postgres from "postgres"; 9 9 import { getBlocksWithTypeLocal } from "src/hooks/queries/useBlocks"; ··· 12 12 import { Database } from "supabase/database.types"; 13 13 import * as Y from "yjs"; 14 14 import { YJSFragmentToString } from "components/Blocks/TextBlock/RenderYJSFragment"; 15 + import { pool } from "supabase/pool"; 15 16 16 17 let supabase = createServerClient<Database>( 17 18 process.env.NEXT_PUBLIC_SUPABASE_API_URL as string, ··· 37 38 email: string, 38 39 token: PermissionToken, 39 40 ) { 40 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 41 + const client = await pool.connect(); 41 42 const db = drizzle(client); 42 43 let newCode = generateCode(); 43 44 let subscription = await db.transaction(async (tx) => { ··· 82 83 `, 83 84 }), 84 85 }); 85 - client.end(); 86 + client.release(); 86 87 return subscription; 87 88 } 88 89
+4 -5
app/api/oauth/[route]/route.ts
··· 1 1 import { createIdentity } from "actions/createIdentity"; 2 2 import { subscribeToPublication } from "app/lish/subscribeToPublication"; 3 - import { drizzle } from "drizzle-orm/postgres-js"; 3 + import { drizzle } from "drizzle-orm/node-postgres"; 4 4 import { cookies } from "next/headers"; 5 5 import { redirect } from "next/navigation"; 6 6 import { NextRequest, NextResponse } from "next/server"; 7 - import postgres from "postgres"; 8 7 import { createOauthClient } from "src/atproto-oauth"; 9 8 import { setAuthToken } from "src/auth"; 10 9 ··· 14 13 ActionAfterSignIn, 15 14 parseActionFromSearchParam, 16 15 } from "./afterSignInActions"; 16 + import { pool } from "supabase/pool"; 17 17 18 18 type OauthRequestClientState = { 19 19 redirect: string | null; ··· 81 81 82 82 return handleAction(s.action, redirectPath); 83 83 } 84 - const client = postgres(process.env.DB_URL as string, { 85 - idle_timeout: 5, 86 - }); 84 + const client = await pool.connect(); 87 85 const db = drizzle(client); 88 86 identity = await createIdentity(db, { atp_did: session.did }); 87 + client.release(); 89 88 } 90 89 let { data: token } = await supabaseServerClient 91 90 .from("email_auth_tokens")
-2
app/api/rpc/[command]/route.ts
··· 1 - import { drizzle } from "drizzle-orm/postgres-js"; 2 1 import { makeRouter } from "../lib"; 3 2 import { push } from "./push"; 4 - import postgres from "postgres"; 5 3 import { createClient } from "@supabase/supabase-js"; 6 4 import { Database } from "supabase/database.types"; 7 5 import { pull } from "./pull";
+4 -3
app/emails/unsubscribe/route.ts
··· 1 1 import { NextRequest } from "next/server"; 2 - import { drizzle } from "drizzle-orm/postgres-js"; 2 + import { drizzle } from "drizzle-orm/node-postgres"; 3 3 import { email_subscriptions_to_entity } from "drizzle/schema"; 4 4 import postgres from "postgres"; 5 5 import { eq } from "drizzle-orm"; 6 + import { pool } from "supabase/pool"; 6 7 7 8 export async function POST(request: NextRequest) { 8 9 let sub_id = request.nextUrl.searchParams.get("sub_id"); 9 10 if (!sub_id) return new Response(null, { status: 404 }); 10 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 11 + const client = await pool.connect(); 11 12 const db = drizzle(client); 12 13 13 14 try { ··· 17 18 } catch (error) { 18 19 console.log(error); 19 20 } 20 - client.end(); 21 + client.release(); 21 22 return new Response(null, { status: 200 }); 22 23 }
+4 -4
app/home/page.tsx
··· 7 7 } from "components/ThemeManager/ThemeProvider"; 8 8 import { EntitySetProvider } from "components/EntitySetProvider"; 9 9 import { createIdentity } from "actions/createIdentity"; 10 - import postgres from "postgres"; 11 - import { drizzle } from "drizzle-orm/postgres-js"; 10 + import { drizzle } from "drizzle-orm/node-postgres"; 12 11 import { IdentitySetter } from "./IdentitySetter"; 13 12 import { LeafletList } from "./LeafletList"; 14 13 import { getIdentityData } from "actions/getIdentityData"; ··· 18 17 import { Media } from "components/Media"; 19 18 import { MyPublicationList } from "./Publications"; 20 19 import { supabaseServerClient } from "supabase/serverClient"; 20 + import { pool } from "supabase/pool"; 21 21 22 22 export default async function Home() { 23 23 let cookieStore = await cookies(); ··· 27 27 else identity = cookieStore.get("identity")?.value; 28 28 let needstosetcookie = false; 29 29 if (!identity) { 30 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 30 + const client = await pool.connect(); 31 31 const db = drizzle(client); 32 32 let newIdentity = await createIdentity(db); 33 - client.end(); 33 + client.release(); 34 34 identity = newIdentity.id; 35 35 needstosetcookie = true; 36 36 }
+4 -4
appview/index.ts
··· 18 18 import { AtUri } from "@atproto/syntax"; 19 19 import { writeFile, readFile } from "fs/promises"; 20 20 import { createIdentity } from "actions/createIdentity"; 21 - import postgres from "postgres"; 22 - import { drizzle } from "drizzle-orm/postgres-js"; 21 + import { drizzle } from "drizzle-orm/node-postgres"; 23 22 import { inngest } from "app/api/inngest/client"; 23 + import { pool } from "supabase/pool"; 24 24 25 25 const cursorFile = process.env.CURSOR_FILE || "/cursor/cursor"; 26 26 ··· 35 35 startCursor = parseInt((await readFile(cursorFile)).toString()); 36 36 } catch (e) {} 37 37 38 - const client = postgres(process.env.DB_URL!); 38 + const client = await pool.connect(); 39 39 const db = drizzle(client); 40 40 async function handleEvent(evt: Event) { 41 41 if (evt.event === "identity") { ··· 257 257 firehose.start(); 258 258 const cleanup = async () => { 259 259 console.log("shutting down firehose..."); 260 - await client.end(); 260 + await client.release(); 261 261 await firehose.destroy(); 262 262 await runner.destroy(); 263 263 process.exit();
+4 -4
components/ShareOptions/getShareLink.ts
··· 1 1 "use server"; 2 2 3 3 import { eq, and } from "drizzle-orm"; 4 - import { drizzle } from "drizzle-orm/postgres-js"; 4 + import { drizzle } from "drizzle-orm/node-postgres"; 5 5 import { permission_token_rights, permission_tokens } from "drizzle/schema"; 6 - import postgres from "postgres"; 6 + import { pool } from "supabase/pool"; 7 7 export async function getShareLink( 8 8 token: { id: string; entity_set: string }, 9 9 rootEntity: string, 10 10 ) { 11 - const client = postgres(process.env.DB_URL as string, { idle_timeout: 5 }); 11 + const client = await pool.connect(); 12 12 const db = drizzle(client); 13 13 let link = await db.transaction(async (tx) => { 14 14 // This will likely error out when if we have multiple permission ··· 65 65 return newToken; 66 66 }); 67 67 68 - client.end(); 68 + client.release(); 69 69 return link; 70 70 }
+2 -1
package-lock.json
··· 50 50 "multiformats": "^13.3.2", 51 51 "next": "^15.5.0", 52 52 "pg": "^8.16.3", 53 - "postgres": "^3.4.4", 54 53 "prosemirror-commands": "^1.5.2", 55 54 "prosemirror-inputrules": "^1.4.0", 56 55 "prosemirror-keymap": "^1.2.2", ··· 14109 14108 "version": "3.4.4", 14110 14109 "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.4.tgz", 14111 14110 "integrity": "sha512-IbyN+9KslkqcXa8AO9fxpk97PA4pzewvpi2B3Dwy9u4zpV32QicaEdgmF3eSQUzdRk7ttDHQejNgAEr4XoeH4A==", 14111 + "optional": true, 14112 + "peer": true, 14112 14113 "engines": { 14113 14114 "node": ">=12" 14114 14115 },
-1
package.json
··· 60 60 "multiformats": "^13.3.2", 61 61 "next": "^15.5.0", 62 62 "pg": "^8.16.3", 63 - "postgres": "^3.4.4", 64 63 "prosemirror-commands": "^1.5.2", 65 64 "prosemirror-inputrules": "^1.4.0", 66 65 "prosemirror-keymap": "^1.2.2",
+12
supabase/pool.ts
··· 1 + import { Pool } from "pg"; 2 + import { attachDatabasePool } from "@vercel/functions"; 3 + import { DbPool } from "@vercel/functions/db-connections"; 4 + 5 + export const pool = new Pool({ 6 + idleTimeoutMillis: 5000, 7 + min: 1, 8 + connectionString: process.env.DB_URL, 9 + }); 10 + 11 + // Attach the pool to ensure idle connections close before suspension 12 + attachDatabasePool(pool as DbPool);