mirror of
https://github.com/CompassConnections/Compass.git
synced 2026-01-08 05:48:12 -05:00
Make local DEV work out of the box
This commit is contained in:
19
.env.example
19
.env.example
@@ -1,28 +1,11 @@
|
||||
# Rename this file to `.env` and fill in the values.
|
||||
# You already have access to basic local functionality (UI, authentication, database read access).
|
||||
|
||||
# Optional variables for the backend server functionality (modifying user data, etc.)
|
||||
|
||||
# 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.
|
||||
GOOGLE_APPLICATION_CREDENTIALS_DEV="[...].json"
|
||||
|
||||
# The URL where your local backend server is running.
|
||||
# You can change the port if needed.
|
||||
NEXT_PUBLIC_API_URL=localhost:8088
|
||||
|
||||
|
||||
# Optional variables for full local functionality
|
||||
|
||||
# For the location / distance filtering features.
|
||||
# Create a free account at https://rapidapi.com/wirefreethought/api/geodb-cities and get an API key.
|
||||
GEODB_API_KEY=
|
||||
|
||||
# For analytics like page views, user actions, feature usage, etc.
|
||||
# Create a free account at https://posthog.com and get a project API key. Should start with "phc_".
|
||||
POSTHOG_KEY=
|
||||
|
||||
# For sending emails (e.g. for user sign up, password reset, notifications, etc.).
|
||||
# Create a free account at https://resend.com and get an API key. Should start with "re_".
|
||||
RESEND_API_KEY=
|
||||
RESEND_KEY=
|
||||
@@ -100,6 +100,8 @@ yarn install
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Almost all the features will work out of the box, so you can skip this step and come back later if you need to test the following services: email, geolocation.
|
||||
|
||||
We can't make the following information public, for security and privacy reasons:
|
||||
- Database, otherwise anyone could access all the user data (including private messages)
|
||||
- Firebase, otherwise anyone could remove users or modify the media files
|
||||
@@ -108,12 +110,7 @@ We can't make the following information public, for security and privacy reasons
|
||||
We separate all those services between production and local development, so that you can code freely without impacting the functioning of the platform.
|
||||
Contributors should use the default keys for local development. Production uses a separate environment with stricter rules and private keys that are not shared.
|
||||
|
||||
Most of the code will work out of the box. All you need to do is creating an `.env` file as a copy of `.env.example`:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
If you do need one of the few remaining services, you need to store your own secrets as environment variables. To do so, simply open `.env` and fill in the variables according to the instructions in the file.
|
||||
If you do need one of the few remaining services, you need to set them up and store your own secrets as environment variables. To do so, simply open `.env` and fill in the variables according to the instructions in the file.
|
||||
|
||||
### Tests
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import * as admin from 'firebase-admin'
|
||||
import {getLocalEnv, initAdmin} from 'shared/init-admin'
|
||||
import {loadSecretsToEnv, getServiceAccountCredentials} from 'common/secrets'
|
||||
import {initAdmin} from 'shared/init-admin'
|
||||
import {loadSecretsToEnv} from 'common/secrets'
|
||||
import {log} from 'shared/utils'
|
||||
import {LOCAL_DEV} from "common/envs/constants";
|
||||
import {IS_LOCAL} from "common/envs/constants";
|
||||
import {METRIC_WRITER} from 'shared/monitoring/metric-writer'
|
||||
import {listen as webSocketListen} from 'shared/websockets/server'
|
||||
|
||||
log('Api server starting up....')
|
||||
|
||||
if (LOCAL_DEV) {
|
||||
if (IS_LOCAL) {
|
||||
initAdmin()
|
||||
} else {
|
||||
const projectId = process.env.GOOGLE_CLOUD_PROJECT
|
||||
@@ -21,9 +21,10 @@ if (LOCAL_DEV) {
|
||||
METRIC_WRITER.start()
|
||||
|
||||
import {app} from './app'
|
||||
import {getServiceAccountCredentials} from "shared/firebase-utils";
|
||||
|
||||
const credentials = LOCAL_DEV
|
||||
? getServiceAccountCredentials(getLocalEnv())
|
||||
const credentials = IS_LOCAL
|
||||
? getServiceAccountCredentials()
|
||||
: // No explicit credentials needed for deployed service.
|
||||
undefined
|
||||
|
||||
@@ -37,6 +38,5 @@ const startupProcess = async () => {
|
||||
})
|
||||
|
||||
webSocketListen(httpServer, '/ws')
|
||||
log('Server started successfully')
|
||||
}
|
||||
startupProcess()
|
||||
startupProcess().then(r => log('Server started successfully'))
|
||||
|
||||
@@ -20,6 +20,7 @@ export const sendEmail = async (
|
||||
console.log(resend, payload, options)
|
||||
|
||||
async function sendEmailThrottle(data: any, options: any) {
|
||||
if (!resend) return { data: null, error: 'No Resend client' }
|
||||
return limit(() => resend.emails.send(data, options))
|
||||
}
|
||||
|
||||
@@ -45,6 +46,11 @@ let resend: Resend | null = null
|
||||
const getResend = () => {
|
||||
if (resend) return resend
|
||||
|
||||
if (!process.env.RESEND_KEY) {
|
||||
console.log('No RESEND_KEY, skipping email send')
|
||||
return
|
||||
}
|
||||
|
||||
const apiKey = process.env.RESEND_KEY as string
|
||||
// console.log(`RESEND_KEY: ${apiKey}`)
|
||||
resend = new Resend(apiKey)
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
import { getLocalEnv, initAdmin } from 'shared/init-admin'
|
||||
import { getServiceAccountCredentials, loadSecretsToEnv } from 'common/secrets'
|
||||
import {
|
||||
createSupabaseDirectClient,
|
||||
type SupabaseDirectClient,
|
||||
} from 'shared/supabase/init'
|
||||
import {initAdmin} from 'shared/init-admin'
|
||||
import {loadSecretsToEnv} from 'common/secrets'
|
||||
import {createSupabaseDirectClient, type SupabaseDirectClient,} from 'shared/supabase/init'
|
||||
import {getServiceAccountCredentials} from "shared/firebase-utils";
|
||||
|
||||
initAdmin()
|
||||
|
||||
export const runScript = async (
|
||||
main: (services: { pg: SupabaseDirectClient }) => Promise<any> | any
|
||||
) => {
|
||||
const env = getLocalEnv()
|
||||
const credentials = getServiceAccountCredentials(env)
|
||||
const credentials = getServiceAccountCredentials()
|
||||
|
||||
await loadSecretsToEnv(credentials)
|
||||
|
||||
const pg = createSupabaseDirectClient()
|
||||
await main({ pg })
|
||||
await main({pg})
|
||||
|
||||
process.exit()
|
||||
}
|
||||
|
||||
3
backend/shared/src/constants.ts
Normal file
3
backend/shared/src/constants.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export const getLocalEnv = () => {
|
||||
return (process.env.ENVIRONMENT?.toUpperCase() ?? 'DEV') as 'PROD' | 'DEV'
|
||||
}
|
||||
23
backend/shared/src/firebase-utils.ts
Normal file
23
backend/shared/src/firebase-utils.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import {readFileSync} from "fs";
|
||||
import {ENV_CONFIG} from "common/envs/constants";
|
||||
|
||||
export const getServiceAccountCredentials = () => {
|
||||
let keyPath = ENV_CONFIG.googleApplicationCredentials
|
||||
if (keyPath == null) {
|
||||
throw new Error(
|
||||
`Please set the GOOGLE_APPLICATION_CREDENTIALS environment variable to contain the path to your key file.`
|
||||
)
|
||||
}
|
||||
|
||||
if (!keyPath.startsWith('/')) {
|
||||
// Make relative paths relative to the current file
|
||||
keyPath = __dirname + '/' + keyPath
|
||||
// console.log(keyPath)
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(readFileSync(keyPath, {encoding: 'utf8'}))
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to load service account key from ${keyPath}: ${e}`)
|
||||
}
|
||||
}
|
||||
13
backend/shared/src/googleApplicationCredentials-dev.json
Normal file
13
backend/shared/src/googleApplicationCredentials-dev.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "service_account",
|
||||
"project_id": "compass-57c3c",
|
||||
"private_key_id": "ce2c7ef4aa137dd4726a8c9398c199ce051d4168",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCNkwHW3buaXX8K\nYWZMIPtHfObK1EmbsIbjbFZtWqcn1Ouw3nj/hCaQQhFmlAvGIP/P0A6d/mlr704o\nK26otjK3S290y/VhI3f2AoMh9af8ptK9mjMbmpwQI7cRu87M/EhbBlYeovntcNfj\n11tsMg83RYUIPXKuQddm2AejRDyhoHsB/QTdSLjDfUIR2pVvHSVbbQwm1cKiFAev\nPm01X3BFLOkzhUCYuzLI1hGXf7G4xm4XCTi2UQGZkI2FYjOgrQcNvkTB33DF0sze\nZCpc8iJsUyQYZxxvsxXd20CwPArsgy+6FU2+dGRrSE6lzwqYU9mnizqtjdp+VUh8\nkppRgZH7AgMBAAECggEAFxMKPjR2grLRZWY5j5fijKTBUvalpp/vZDrAnWMkklvk\nLDgeXXry9Bkoj+D6SEkRmJPPBhY0pXhj8y0dBJdpjbFYUZ96d2IaB7kiGVNaFVY1\nS9zJjqq02/aOPHAxRPyraFaQi77BYF8/eK2dg3VnQHlutMibG+a0TllQaV5SSX9J\n7cj4C6RX2p8Zvrmu6RsQ+dQWZFMwT8oHhuKCrL8+iw6bXYH1bSvxHLS+sCreIK7d\nYvY/DPxlC1rGaK8ovH5nuc3nQ+ECsWcDjcqjg4SmI7VwPpWeJ97exf3BGUmSFSOC\nCNfWu6bqhWleBkRozRCAuzQwesLkr38MsjU1iZS4VQKBgQDAG75trRLUHvuCoPpu\nHw4Ev1qpqVa1rE/16Zmzp7/wzoOP7yqoW2Og2adE5N2KUxR48nAMnR/uwRQcvlhX\n2Y7qEprl0AkXRXpneGiPFD/vzkTAjRWZdd0sIpo3+KCZcoO9OsJ8eA5Ch0bthv6q\nJBjd9VwgIaS5gd/eX76xBMV6ZQKBgQC8qL+bc6S3EiGoGf+Fzm+XXfXuVn0VA2sx\nhJjV/tfxxv6EIO90COsKy3CgaNOjU+NZ6jx+Kq07c4HBPA3c43qSRNUkWfQyyQgA\nPV3f5ZP40z+U4QnbhWSVSch91FCxwAnL9N7/KM77gAsHCdUuMlCVAYDr6JfDZiJR\nQ9X3cfLk3wKBgHn4o31rJ8s6KKIVpysH2JS3Ec8qzvzl/Ja7zHS+iyVPWUSnq0Pd\nUnIr/wHE9cv/V746312C3WVvfV+KkvikDxMa4PIMldkKqd7MGkbNqpKNOiWu7gnT\nRaviBFyJJR6IEJCyoAz7BMLEtQnWbhaEeK1kPSvBcJ6/kO3ViHNH/kHpAoGBAJ2Z\nLi8TBOc1y03dIfrKP6goAtiuAWF7cKF2DiK99/DudhE0XjQFeyuSVSx7RUisPEER\njqUqy3ndfOhKXZ5HnU3xGEh8qKWAECH7IZ927gyvk+6vqwdpwGOBtm1+3kYOkWCC\n14I5ueaYyR2BFke4Gl7PWb44mAbQHBzc2TITS3/rAoGBAKsCx9IQk1p0Am/+/NcW\nBnxnE5iNmaX3H4+pmtShl8gXxaI1DWnB7WbqjDOCu9HCnPZUdLXbrserny+ZSyNU\nnHE1InQn7T/xM7RXZRkZk09qmSRicXh6kS+cSBg1xU5vIPPsBTrWVmg74L9guNdo\nYQXUSGJaJbCZ6N35oz+Qf3NB\n-----END PRIVATE KEY-----\n",
|
||||
"client_email": "dev-contributors@compass-57c3c.iam.gserviceaccount.com",
|
||||
"client_id": "118371540020807340605",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://oauth2.googleapis.com/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/dev-contributors%40compass-57c3c.iam.gserviceaccount.com",
|
||||
"universe_domain": "googleapis.com"
|
||||
}
|
||||
@@ -1,16 +1,12 @@
|
||||
import * as admin from 'firebase-admin'
|
||||
|
||||
import { getServiceAccountCredentials } from 'common/secrets'
|
||||
|
||||
export const getLocalEnv = () => {
|
||||
return (process.env.ENV?.toUpperCase() ?? 'STAGING') as 'PROD' | 'DEV'
|
||||
}
|
||||
import {getServiceAccountCredentials} from "shared/firebase-utils";
|
||||
|
||||
// Locally initialize Firebase Admin.
|
||||
export const initAdmin = () => {
|
||||
try {
|
||||
const env = getLocalEnv()
|
||||
const serviceAccount = getServiceAccountCredentials(env)
|
||||
const serviceAccount = getServiceAccountCredentials()
|
||||
console.log(
|
||||
`Initializing connection to ${serviceAccount.project_id} Firebase...`
|
||||
)
|
||||
|
||||
@@ -36,11 +36,11 @@ export type SupabaseTransaction = ITask<{}>
|
||||
export type SupabaseDirectClient = IDatabase<{}, IClient> | SupabaseTransaction
|
||||
|
||||
export function getInstanceId() {
|
||||
return process.env.SUPABASE_INSTANCE_ID ?? ENV_CONFIG.supabaseInstanceId
|
||||
return ENV_CONFIG.supabaseInstanceId
|
||||
}
|
||||
|
||||
export function getSupabasePwd() {
|
||||
return ENV_CONFIG.supabaseServiceRoleKey ?? process.env.SUPABASE_DB_PASSWORD
|
||||
return ENV_CONFIG.supabasePwd
|
||||
}
|
||||
|
||||
const newClient = (
|
||||
@@ -55,7 +55,7 @@ const newClient = (
|
||||
// This host is IPV4 compatible, for the google cloud VM
|
||||
host: 'aws-1-us-west-1.pooler.supabase.com',
|
||||
port: 5432,
|
||||
user: `postgres.ltzepxnhhnrnvovqblfr`,
|
||||
user: `postgres.${instanceId}`,
|
||||
password: password,
|
||||
database: 'postgres',
|
||||
pool_mode: 'session',
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
ServerMessage,
|
||||
CLIENT_MESSAGE_SCHEMA,
|
||||
} from 'common/api/websockets'
|
||||
import {LOCAL_DEV} from "common/envs/constants";
|
||||
import {IS_LOCAL} from "common/envs/constants";
|
||||
|
||||
const SWITCHBOARD = new Switchboard()
|
||||
|
||||
@@ -107,7 +107,7 @@ export function broadcastMulti(topics: string[], data: BroadcastPayload) {
|
||||
|
||||
// it isn't secure to do this in prod for auth reasons (maybe?)
|
||||
// but it's super convenient for testing
|
||||
if (LOCAL_DEV) {
|
||||
if (IS_LOCAL) {
|
||||
const msg = { type: 'broadcast', topic: '*', topics, data }
|
||||
sendToSubscribers('*', msg)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ regen-types-prod:
|
||||
cd ../../common && npx prettier --write ./src/supabase/schema.ts
|
||||
|
||||
regen-types-dev:
|
||||
npx supabase gen types typescript --project-id ltzepxnhhnrnvovqblfr --schema public > ../../common/src/supabase/schema.ts
|
||||
npx supabase gen types typescript --project-id zbspxezubpzxmuxciurg --schema public > ../../common/src/supabase/schema.ts
|
||||
cd ../../common && npx prettier --write ./src/supabase/schema.ts
|
||||
|
||||
regen-schema:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ENV_CONFIG } from 'common/envs/constants'
|
||||
import {BACKEND_DOMAIN} from 'common/envs/constants'
|
||||
|
||||
type ErrorCode =
|
||||
| 400 // your input is bad (like zod is mad)
|
||||
@@ -11,6 +11,7 @@ type ErrorCode =
|
||||
export class APIError extends Error {
|
||||
code: ErrorCode
|
||||
details?: unknown
|
||||
|
||||
constructor(code: ErrorCode, message: string, details?: unknown) {
|
||||
super(message)
|
||||
this.code = code
|
||||
@@ -19,20 +20,19 @@ export class APIError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
const prefix = 'v0'
|
||||
|
||||
export function pathWithPrefix(path: string) {
|
||||
return `/v0${path}`
|
||||
return `/${prefix}${path}`
|
||||
}
|
||||
|
||||
export function getWebsocketUrl() {
|
||||
const endpoint = process.env.NEXT_PUBLIC_API_URL ?? ENV_CONFIG.apiEndpoint
|
||||
const protocol = endpoint.startsWith('localhost') ? 'ws' : 'wss'
|
||||
const protocol = BACKEND_DOMAIN.startsWith('localhost') ? 'ws' : 'wss'
|
||||
|
||||
return `${protocol}://${endpoint}/ws`
|
||||
return `${protocol}://${BACKEND_DOMAIN}/ws`
|
||||
}
|
||||
|
||||
export function getApiUrl(path: string) {
|
||||
const endpoint = process.env.NEXT_PUBLIC_API_URL ?? ENV_CONFIG.apiEndpoint
|
||||
const protocol = endpoint.startsWith('localhost') ? 'http' : 'https'
|
||||
const prefix = 'v0'
|
||||
return `${protocol}://${endpoint}/${prefix}/${path}`
|
||||
const protocol = BACKEND_DOMAIN.startsWith('localhost') ? 'http' : 'https'
|
||||
return `${protocol}://${BACKEND_DOMAIN}/${prefix}/${path}`
|
||||
}
|
||||
|
||||
@@ -15,7 +15,13 @@ export function isModId(id: string) {
|
||||
return MOD_IDS.includes(id)
|
||||
}
|
||||
|
||||
export const DOMAIN = ENV_CONFIG.domain
|
||||
export const LOCAL_WEB_DOMAIN = 'localhost:3000';
|
||||
export const LOCAL_BACKEND_DOMAIN = 'localhost:8088';
|
||||
export const IS_LOCAL = !process.env.VERCEL && !process.env.K_SERVICE;
|
||||
console.log(IS_LOCAL ? 'Running in local mode' : 'Running in deployed mode', isProd() ? '(prod)' : '(dev)');
|
||||
|
||||
export const DOMAIN = IS_LOCAL ? LOCAL_WEB_DOMAIN : ENV_CONFIG.domain
|
||||
export const BACKEND_DOMAIN = IS_LOCAL ? LOCAL_BACKEND_DOMAIN : ENV_CONFIG.backendDomain
|
||||
export const FIREBASE_CONFIG = ENV_CONFIG.firebaseConfig
|
||||
export const PROJECT_ID = ENV_CONFIG.firebaseConfig.projectId
|
||||
|
||||
@@ -98,7 +104,4 @@ export const RESERVED_PATHS = [
|
||||
'users',
|
||||
'web',
|
||||
'welcome',
|
||||
]
|
||||
|
||||
export const LOCAL_WEB_URL = 'http://localhost:3000';
|
||||
export const LOCAL_DEV = process.env.GOOGLE_CLOUD_PROJECT == null
|
||||
]
|
||||
@@ -2,9 +2,12 @@ import { EnvConfig, PROD_CONFIG } from './prod'
|
||||
|
||||
export const DEV_CONFIG: EnvConfig = {
|
||||
...PROD_CONFIG,
|
||||
domain: 'dev.compassmeet.com',
|
||||
backendDomain: 'api.dev.compassmeet.com',
|
||||
supabaseInstanceId: 'zbspxezubpzxmuxciurg',
|
||||
supabaseServiceRoleKey: '09wATRREfAzyL5pc', // For database write access (dev). A 16-character password with digits and letters.
|
||||
supabasePwd: 'FO3y0G7chzdq6aE7', // For database write access (dev). A 16-character password with digits and letters.
|
||||
supabaseAnonKey: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Inpic3B4ZXp1YnB6eG11eGNpdXJnIiwicm9sZSI6ImFub24iLCJpYXQiOjE3NTc2ODM0MTMsImV4cCI6MjA3MzI1OTQxM30.ZkM7zlawP8Nke0T3KJrqpOQ4DzqPaXTaJXLC2WU8Y7c',
|
||||
googleApplicationCredentials: 'googleApplicationCredentials-dev.json',
|
||||
firebaseConfig: {
|
||||
apiKey: "AIzaSyBspL9glBXWbMsjmtt36dgb2yU0YGGhzKo",
|
||||
authDomain: "compass-57c3c.firebaseapp.com",
|
||||
@@ -15,5 +18,5 @@ export const DEV_CONFIG: EnvConfig = {
|
||||
appId: "1:297460199314:web:c45678c54285910e255b4b",
|
||||
measurementId: "G-N6LZ64EMJ2",
|
||||
region: 'us-west1',
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
@@ -3,9 +3,10 @@ export type EnvConfig = {
|
||||
firebaseConfig: FirebaseConfig
|
||||
supabaseInstanceId: string
|
||||
supabaseAnonKey: string
|
||||
supabaseServiceRoleKey?: string
|
||||
supabasePwd?: string
|
||||
posthogKey: string
|
||||
apiEndpoint: string
|
||||
backendDomain: string
|
||||
googleApplicationCredentials: string
|
||||
|
||||
// IDs for v2 cloud functions -- find these by deploying a cloud function and
|
||||
// examining the URL, https://[name]-[cloudRunId]-[cloudRunRegion].a.run.app
|
||||
@@ -33,6 +34,11 @@ type FirebaseConfig = {
|
||||
export const PROD_CONFIG: EnvConfig = {
|
||||
posthogKey: 'phc_tFvQzHiMVdaAIgE38xqYomMN8q8SB5K45fqmkKNjfBU',
|
||||
domain: 'compassmeet.com',
|
||||
backendDomain: 'api.compassmeet.com',
|
||||
supabaseInstanceId: 'ltzepxnhhnrnvovqblfr',
|
||||
supabaseAnonKey: process.env.NEXT_PUBLIC_SUPABASE_KEY || '',
|
||||
supabasePwd: process.env.SUPABASE_DB_PASSWORD || '',
|
||||
googleApplicationCredentials: process.env.GOOGLE_APPLICATION_CREDENTIALS || '',
|
||||
firebaseConfig: {
|
||||
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY || '',
|
||||
authDomain: "compass-130ba.firebaseapp.com",
|
||||
@@ -46,12 +52,8 @@ export const PROD_CONFIG: EnvConfig = {
|
||||
},
|
||||
cloudRunId: 'w3txbmd3ba',
|
||||
cloudRunRegion: 'uc',
|
||||
supabaseInstanceId: 'ltzepxnhhnrnvovqblfr',
|
||||
supabaseAnonKey: process.env.NEXT_PUBLIC_SUPABASE_KEY || '',
|
||||
apiEndpoint: 'api.compassmeet.com',
|
||||
adminIds: [
|
||||
'0vaZsIJk9zLVOWY4gb61gTrRIU73', // Martin
|
||||
],
|
||||
|
||||
faviconPath: '/favicon.ico',
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { readFileSync } from 'fs'
|
||||
import { SecretManagerServiceClient } from '@google-cloud/secret-manager'
|
||||
import { zip } from 'lodash'
|
||||
import {SecretManagerServiceClient} from '@google-cloud/secret-manager'
|
||||
import {zip} from 'lodash'
|
||||
import {IS_LOCAL} from "common/envs/constants";
|
||||
|
||||
// List of secrets that are available to backend (api, functions, scripts, etc.)
|
||||
// Edit them at:
|
||||
@@ -27,6 +27,9 @@ type SecretId = (typeof secrets)[number]
|
||||
// For deployed google cloud service, no credential is needed.
|
||||
// For local and Vercel deployments: requires credentials json object.
|
||||
export const getSecrets = async (credentials?: any, ...ids: SecretId[]) => {
|
||||
if (!ids.length && IS_LOCAL) return {}
|
||||
|
||||
console.log('Fetching secrets...')
|
||||
let client: SecretManagerServiceClient
|
||||
if (credentials) {
|
||||
const projectId = credentials['project_id']
|
||||
@@ -71,29 +74,3 @@ export const loadSecretsToEnv = async (credentials?: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Get service account credentials from Vercel environment variable or local file.
|
||||
export const getServiceAccountCredentials = (env: 'PROD' | 'DEV') => {
|
||||
// Vercel environment variable for service credential.
|
||||
const value =
|
||||
env === 'PROD'
|
||||
? process.env.PROD_FIREBASE_SERVICE_ACCOUNT_KEY
|
||||
: process.env.DEV_FIREBASE_SERVICE_ACCOUNT_KEY
|
||||
if (value && !process.env.LOCAL) {
|
||||
return JSON.parse(value)
|
||||
}
|
||||
|
||||
// Local environment variable for service credential.
|
||||
const envVar = `GOOGLE_APPLICATION_CREDENTIALS_${env}`
|
||||
const keyPath = process.env[envVar]
|
||||
if (keyPath == null) {
|
||||
throw new Error(
|
||||
`Please set the ${envVar} environment variable to contain the path to your ${env} environment key file.`
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(readFileSync(keyPath, { encoding: 'utf8' }))
|
||||
} catch (e) {
|
||||
throw new Error(`Failed to load service account key from ${keyPath}.`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {DOMAIN, LOCAL_DEV, LOCAL_WEB_URL} from 'common/envs/constants'
|
||||
import {DOMAIN} from 'common/envs/constants'
|
||||
|
||||
// opengraph functions that run in static props or client-side, but not in the edge (in image creation)
|
||||
|
||||
@@ -10,5 +10,5 @@ export function buildOgUrl<P extends Record<string, string>>(
|
||||
const generateUrlParams = (params: P) =>
|
||||
new URLSearchParams(params).toString()
|
||||
|
||||
return `https://${domain ?? LOCAL_DEV ? LOCAL_WEB_URL : DOMAIN}/api/og/${endpoint}?` + generateUrlParams(props)
|
||||
return `https://${domain ?? DOMAIN}/api/og/${endpoint}?` + generateUrlParams(props)
|
||||
}
|
||||
|
||||
@@ -12,14 +12,16 @@
|
||||
],
|
||||
"scripts": {
|
||||
"verify": "yarn --cwd=common verify:dir; yarn --cwd=web verify:dir; yarn --cwd=backend/shared verify:dir",
|
||||
"lint": "yarn --cwd=web lint-fix; eslint common --fix ; eslint backend/api --fix ; eslint backend/shared --fix", "dev": "./scripts/run_local.sh dev",
|
||||
"lint": "yarn --cwd=web lint-fix; eslint common --fix ; eslint backend/api --fix ; eslint backend/shared --fix",
|
||||
"dev": "./scripts/run_local.sh dev",
|
||||
"prod": "./scripts/run_local.sh prod",
|
||||
"clean-install": "./scripts/install.sh",
|
||||
"migrate": "./scripts/migrate.sh",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:coverage": "jest --coverage",
|
||||
"test:update": "jest --updateSnapshot"
|
||||
"test:update": "jest --updateSnapshot",
|
||||
"postinstall": "./scripts/post_install.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"@playwright/test": "^1.54.2",
|
||||
|
||||
10
scripts/post_install.sh
Executable file
10
scripts/post_install.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$(dirname "$0")"/..
|
||||
|
||||
if [ ! -f .env ]; then
|
||||
cp .env.example .env
|
||||
echo ".env file created from .env.example"
|
||||
fi
|
||||
@@ -4,26 +4,27 @@ set -e
|
||||
|
||||
cd "$(dirname "$0")"/..
|
||||
|
||||
ENV=${1:-prod}
|
||||
PROJECT=$2
|
||||
case $ENV in
|
||||
dev)
|
||||
NEXT_ENV=DEV ;;
|
||||
prod)
|
||||
NEXT_ENV=PROD ;;
|
||||
*)
|
||||
echo "Invalid environment; must be dev or prod."
|
||||
exit 1
|
||||
ENVIRONMENT=${1:-dev}
|
||||
echo "Running in $ENVIRONMENT environment"
|
||||
case $ENVIRONMENT in
|
||||
dev)
|
||||
NEXT_ENV=DEV
|
||||
;;
|
||||
prod)
|
||||
NEXT_ENV=PROD
|
||||
;;
|
||||
*)
|
||||
echo "Unknown environment: $ENVIRONMENT"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
WEB_DIR=web
|
||||
|
||||
source .env
|
||||
|
||||
npx dotenv -e .env -- npx concurrently \
|
||||
-n API,NEXT,TS \
|
||||
-c white,magenta,cyan \
|
||||
"cross-env ENV=$NEXT_ENV ENVIRONMENT=$NEXT_ENV yarn --cwd=backend/api dev" \
|
||||
"cross-env ENVIRONMENT=$NEXT_ENV yarn --cwd=backend/api dev" \
|
||||
"cross-env NEXT_PUBLIC_FIREBASE_ENV=$NEXT_ENV yarn --cwd=$WEB_DIR serve" \
|
||||
"cross-env yarn --cwd=$WEB_DIR ts-watch"
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ module.exports = {
|
||||
{ hostname: 'picsum.photos' },
|
||||
{ hostname: '*.giphy.com' },
|
||||
{ hostname: 'ui-avatars.com' },
|
||||
{ hostname: 'localhost' },
|
||||
],
|
||||
},
|
||||
webpack: (config) => {
|
||||
|
||||
Reference in New Issue
Block a user