diff --git a/.env.example b/.env.example index 06b67c08..744d5774 100644 --- a/.env.example +++ b/.env.example @@ -3,10 +3,6 @@ # Optional variables for the backend server functionality (modifying user data, etc.) -# For database write access (dev). -# A 16-character password with digits and letters. -SUPABASE_DB_PASSWORD=09wATRREfAzyL5pc - # For Firebase access. # Open a GitHub issue with your contribution ideas and an admin will give you the key. # TODO: find a way to give anyone moderate access to dev firebase. diff --git a/backend/shared/src/supabase/init.ts b/backend/shared/src/supabase/init.ts index 58e107f0..0348b5aa 100644 --- a/backend/shared/src/supabase/init.ts +++ b/backend/shared/src/supabase/init.ts @@ -1,14 +1,12 @@ -import pgPromise from 'pg-promise' -export { SupabaseClient } from 'common/supabase/utils' -import { DEV_CONFIG } from 'common/envs/dev' -import { PROD_CONFIG } from 'common/envs/prod' -import { metrics, log, isProd } from '../utils' -import { IDatabase, ITask } from 'pg-promise' -import { IClient } from 'pg-promise/typescript/pg-subset' -import { HOUR_MS } from 'common/util/time' -import { METRICS_INTERVAL_MS } from 'shared/monitoring/metric-writer' -import { getMonitoringContext } from 'shared/monitoring/context' -import { type IConnectionParameters } from 'pg-promise/typescript/pg-subset' +import pgPromise, {IDatabase, ITask} from 'pg-promise' +import {log, metrics} from '../utils' +import {IClient, type IConnectionParameters} from 'pg-promise/typescript/pg-subset' +import {HOUR_MS} from 'common/util/time' +import {METRICS_INTERVAL_MS} from 'shared/monitoring/metric-writer' +import {getMonitoringContext} from 'shared/monitoring/context' +import {ENV_CONFIG} from "common/envs/constants"; + +export {SupabaseClient} from 'common/supabase/utils' export const pgp = pgPromise({ error(err: any, e: pgPromise.IEventContext) { @@ -21,9 +19,9 @@ export const pgp = pgPromise({ query() { const ctx = getMonitoringContext() if (ctx?.endpoint) { - metrics.inc('pg/query_count', { endpoint: ctx.endpoint }) + metrics.inc('pg/query_count', {endpoint: ctx.endpoint}) } else if (ctx?.job) { - metrics.inc('pg/query_count', { job: ctx.job }) + metrics.inc('pg/query_count', {job: ctx.job}) } else { metrics.inc('pg/query_count') } @@ -38,10 +36,11 @@ export type SupabaseTransaction = ITask<{}> export type SupabaseDirectClient = IDatabase<{}, IClient> | SupabaseTransaction export function getInstanceId() { - return ( - process.env.SUPABASE_INSTANCE_ID ?? - (isProd() ? PROD_CONFIG.supabaseInstanceId : DEV_CONFIG.supabaseInstanceId) - ) + return process.env.SUPABASE_INSTANCE_ID ?? ENV_CONFIG.supabaseInstanceId +} + +export function getSupabasePwd() { + return ENV_CONFIG.supabaseServiceRoleKey ?? process.env.SUPABASE_DB_PASSWORD } const newClient = ( @@ -50,7 +49,7 @@ const newClient = ( password?: string } & IConnectionParameters ) => { - const { instanceId, password, ...settings } = props + const {instanceId, password, ...settings} = props const config = { // This host is IPV4 compatible, for the google cloud VM @@ -60,7 +59,7 @@ const newClient = ( password: password, database: 'postgres', pool_mode: 'session', - ssl: { rejectUnauthorized: false }, + ssl: {rejectUnauthorized: false}, family: 4, // <- forces IPv4 ...settings, } @@ -72,6 +71,7 @@ const newClient = ( // Use one connection to avoid WARNING: Creating a duplicate database object for the same connection. let pgpDirect: IDatabase<{}, IClient> | null = null + export function createSupabaseDirectClient( instanceId?: string, password?: string @@ -83,7 +83,7 @@ export function createSupabaseDirectClient( "Can't connect to Supabase; no process.env.SUPABASE_INSTANCE_ID and no instance ID in config." ) } - password = password ?? process.env.SUPABASE_DB_PASSWORD + password = password ?? getSupabasePwd() if (!password) { throw new Error( "Can't connect to Supabase; no process.env.SUPABASE_DB_PASSWORD." @@ -101,10 +101,10 @@ export function createSupabaseDirectClient( pool.on('acquire', () => metrics.inc('pg/connections_acquired')) pool.on('release', () => metrics.inc('pg/connections_released')) setInterval(() => { - metrics.set('pg/pool_connections', pool.waitingCount, { state: 'waiting' }) - metrics.set('pg/pool_connections', pool.idleCount, { state: 'idle' }) - metrics.set('pg/pool_connections', pool.expiredCount, { state: 'expired' }) - metrics.set('pg/pool_connections', pool.totalCount, { state: 'total' }) + metrics.set('pg/pool_connections', pool.waitingCount, {state: 'waiting'}) + metrics.set('pg/pool_connections', pool.idleCount, {state: 'idle'}) + metrics.set('pg/pool_connections', pool.expiredCount, {state: 'expired'}) + metrics.set('pg/pool_connections', pool.totalCount, {state: 'total'}) }, METRICS_INTERVAL_MS) return (pgpDirect = client) } @@ -114,7 +114,7 @@ export const createShortTimeoutDirectClient = () => { if (shortTimeoutPgpClient) return shortTimeoutPgpClient shortTimeoutPgpClient = newClient({ instanceId: getInstanceId(), - password: process.env.SUPABASE_DB_PASSWORD, + password: getSupabasePwd(), query_timeout: 1000 * 30, max: 20, }) diff --git a/backend/shared/src/utils.ts b/backend/shared/src/utils.ts index e31406b1..77b40f1b 100644 --- a/backend/shared/src/utils.ts +++ b/backend/shared/src/utils.ts @@ -1,18 +1,20 @@ import {createSupabaseDirectClient, SupabaseDirectClient,} from 'shared/supabase/init' -import * as admin from 'firebase-admin' import {convertPrivateUser, convertUser} from 'common/supabase/users' import {log, type Logger} from 'shared/monitoring/log' import {metrics} from 'shared/monitoring/metrics' -export { metrics } -export { log, type Logger } +export {metrics} +export {log, type Logger} export const getUser = async ( userId: string, pg: SupabaseDirectClient = createSupabaseDirectClient() ) => { return await pg.oneOrNone( - `select * from users where id = $1 limit 1`, + `select * + from users + where id = $1 + limit 1`, [userId], convertUser ) @@ -23,7 +25,10 @@ export const getPrivateUser = async ( pg: SupabaseDirectClient = createSupabaseDirectClient() ) => { return await pg.oneOrNone( - `select * from private_users where id = $1 limit 1`, + `select * + from private_users + where id = $1 + limit 1`, [userId], convertPrivateUser ) @@ -34,7 +39,9 @@ export const getUserByUsername = async ( pg: SupabaseDirectClient = createSupabaseDirectClient() ) => { const res = await pg.oneOrNone( - `select * from users where username = $1`, + `select * + from users + where username = $1`, username ) @@ -46,20 +53,11 @@ export const getPrivateUserByKey = async ( pg: SupabaseDirectClient = createSupabaseDirectClient() ) => { return await pg.oneOrNone( - `select * from private_users where data->>'apiKey' = $1 limit 1`, + `select * + from private_users + where data ->> 'apiKey' = $1 + limit 1`, [apiKey], convertPrivateUser ) } - -// TODO: deprecate in favor of common/src/envs/is-prod.ts -export const isProd = () => { - // mqp: kind of hacky rn. the first clause is for cloud run API service, - // second clause is for local scripts and cloud functions - if (process.env.ENVIRONMENT) { - return process.env.ENVIRONMENT == 'PROD' - } else { - return admin.app().options.projectId === 'compass-130ba' - } -} - diff --git a/common/src/envs/constants.ts b/common/src/envs/constants.ts index 8413666a..1c602ad7 100644 --- a/common/src/envs/constants.ts +++ b/common/src/envs/constants.ts @@ -1,20 +1,11 @@ import {DEV_CONFIG} from './dev' -import {EnvConfig, PROD_CONFIG} from './prod' - -// Valid in web client & Vercel deployments only. -export const ENV = (process.env.NEXT_PUBLIC_FIREBASE_ENV ?? 'PROD') as - | 'PROD' - | 'DEV' - -export const CONFIGS: { [env: string]: EnvConfig } = { - PROD: PROD_CONFIG, - DEV: DEV_CONFIG, -} +import {PROD_CONFIG} from './prod' +import {isProd} from "common/envs/is-prod"; export const MAX_DESCRIPTION_LENGTH = 16000 export const MAX_ANSWER_LENGTH = 240 -export const ENV_CONFIG = CONFIGS[ENV] +export const ENV_CONFIG = isProd() ? PROD_CONFIG : DEV_CONFIG export function isAdminId(id: string) { return ENV_CONFIG.adminIds.includes(id) @@ -23,6 +14,7 @@ export function isAdminId(id: string) { export function isModId(id: string) { return MOD_IDS.includes(id) } + export const DOMAIN = ENV_CONFIG.domain export const FIREBASE_CONFIG = ENV_CONFIG.firebaseConfig export const PROJECT_ID = ENV_CONFIG.firebaseConfig.projectId diff --git a/common/src/envs/dev.ts b/common/src/envs/dev.ts index 5c60b7bd..ab161268 100644 --- a/common/src/envs/dev.ts +++ b/common/src/envs/dev.ts @@ -3,6 +3,7 @@ import { EnvConfig, PROD_CONFIG } from './prod' export const DEV_CONFIG: EnvConfig = { ...PROD_CONFIG, supabaseInstanceId: 'zbspxezubpzxmuxciurg', + supabaseServiceRoleKey: '09wATRREfAzyL5pc', // For database write access (dev). A 16-character password with digits and letters. supabaseAnonKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inpic3B4ZXp1YnB6eG11eGNpdXJnIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTc2ODM0MTMsImV4cCI6MjA3MzI1OTQxM30.ZkM7zlawP8Nke0T3KJrqpOQ4DzqPaXTaJXLC2WU8Y7c', firebaseConfig: { apiKey: "AIzaSyBspL9glBXWbMsjmtt36dgb2yU0YGGhzKo", diff --git a/common/src/envs/prod.ts b/common/src/envs/prod.ts index b85e664b..b6b6a8f4 100644 --- a/common/src/envs/prod.ts +++ b/common/src/envs/prod.ts @@ -3,6 +3,7 @@ export type EnvConfig = { firebaseConfig: FirebaseConfig supabaseInstanceId: string supabaseAnonKey: string + supabaseServiceRoleKey?: string posthogKey: string apiEndpoint: string diff --git a/web/components/site-logo.tsx b/web/components/site-logo.tsx index 4438a106..53cc7723 100644 --- a/web/components/site-logo.tsx +++ b/web/components/site-logo.tsx @@ -1,19 +1,19 @@ import Link from 'next/link' import clsx from 'clsx' -import { ENV } from 'common/envs/constants' -import { Row } from 'web/components/layout/row' +import {Row} from 'web/components/layout/row' import FavIcon from "web/public/FavIcon"; +import {isProd} from "common/envs/is-prod"; export default function SiteLogo(props: { noLink?: boolean className?: string }) { - const { noLink, className } = props + const {noLink, className} = props const inner = ( <>
- {ENV == 'DEV' ? 'Compass dev' : 'Compass'} + {isProd() ? 'Compass' : 'Compass dev'}
)