2023-02-13 12:41:30 +00:00
import * as process from "process" ;
import * as convict from "convict" ;
2023-03-13 11:00:35 +00:00
import * as Metamigo from "@digiresilience/metamigo-common" ;
2023-02-13 12:41:30 +00:00
import { defState } from "@digiresilience/montar" ;
export const configSchema = {
db : {
connection : {
doc : "The postgres connection url." ,
format : "uri" ,
default : "postgresql://metamigo:metamigo@127.0.0.1:5435/metamigo_dev" ,
env : "DATABASE_URL" ,
sensitive : true ,
} ,
name : {
doc : "The name of the postgres database" ,
format : String ,
default : "metamigo_dev" ,
env : "DATABASE_NAME" ,
} ,
owner : {
doc : "The username of the postgres database owner" ,
format : String ,
default : "metamigo" ,
env : "DATABASE_OWNER" ,
} ,
} ,
worker : {
connection : {
doc : "The postgres connection url for the worker database." ,
format : "uri" ,
default : "postgresql://metamigo:metamigo@127.0.0.1:5435/metamigo_dev" ,
env : "WORKER_DATABASE_URL" ,
} ,
concurrency : {
doc : "The number of jobs to run concurrently" ,
default : 1 ,
format : "positiveInt" ,
env : "WORKER_CONCURRENT_JOBS" ,
} ,
pollInterval : {
doc : "How long to wait between polling for jobs in milliseconds (for jobs scheduled in the future/retries)" ,
default : 2000 ,
format : "positiveInt" ,
env : "WORKER_POLL_INTERVAL_MS" ,
} ,
} ,
postgraphile : {
auth : {
doc : "The postgres role that postgraphile logs in with" ,
format : String ,
default : "metamigo_graphile_auth" ,
env : "DATABASE_AUTHENTICATOR" ,
} ,
appRootConnection : {
doc : "The postgres root/superuser connection url for development mode so PG can watch the schema changes, this is strangely named in the postgraphile API 'ownerConnectionString'" ,
format : String ,
default : "postgresql://postgres:metamigo@127.0.0.1:5435/metamigo_dev" ,
env : "APP_ROOT_DATABASE_URL" ,
} ,
authConnection : {
doc : "The postgres connection URL for postgraphile, must not be superuser and must have limited privs." ,
format : String ,
default :
"postgresql://metamigo_graphile_auth:metamigo@127.0.0.1:5435/metamigo_dev" ,
env : "DATABASE_AUTH_URL" ,
} ,
visitor : {
doc : "The postgres role that postgraphile switches to" ,
format : String ,
default : "app_postgraphile" ,
env : "DATABASE_VISITOR" ,
} ,
schema : {
doc : "The schema postgraphile should expose with graphql" ,
format : String ,
default : "app_public" ,
} ,
enableGraphiql : {
doc : "Whether to enable the graphiql web interface or not" ,
format : "Boolean" ,
default : false ,
env : "ENABLE_GRAPHIQL" ,
} ,
} ,
dev : {
shadowConnection : {
doc : "The shadow databse connection url used by postgraphile-migrate. Not needed in production." ,
format : "uri" ,
default : "postgresql://metamigo:metamigo@127.0.0.1:5435/metamigo_shadow" ,
env : "SHADOW_DATABASE_URL" ,
sensitive : true ,
} ,
rootConnection : {
doc : "The postgres root/superuser connection url for testing only, database must NOT be the app database. Not needed in production." ,
format : "uri" ,
default : "postgresql://postgres:metamigo@127.0.0.1:5435/template1" ,
env : "ROOT_DATABASE_URL" ,
sensitive : true ,
} ,
} ,
frontend : {
url : {
doc : "The url the frontend can be accessed at" ,
format : "url" ,
default : "http://localhost:3000" ,
env : "FRONTEND_URL" ,
} ,
apiUrl : {
doc : "The url the api backend can be accessed at from the frontend server" ,
format : "url" ,
default : "http://localhost:3001" ,
env : "API_URL" ,
} ,
} ,
nextAuth : {
secret : {
doc : "A random string used to hash tokens, sign cookies and generate crytographic keys. Shared with the api backend." ,
format : String ,
default : undefined ,
env : "NEXTAUTH_SECRET" ,
sensitive : true ,
} ,
audience : {
doc : "We will add this string as the `aud` claim to our JWT token, if empty or not present defaults to `frontend.url`" ,
format : String ,
default : "" ,
env : "NEXTAUTH_AUDIENCE" ,
} ,
signingKeyB64 : {
doc : "A base64 encoded JWK.Key used for JWT signing" ,
format : String ,
default : undefined ,
env : "NEXTAUTH_SIGNING_KEY_B64" ,
sensitive : true ,
} ,
encryptionKeyB64 : {
doc : "A base64 encoded JWK.Key used for JWT encryption" ,
format : String ,
default : undefined ,
env : "NEXTAUTH_ENCRYPTION_KEY_B64" ,
sensitive : true ,
} ,
signingKey : {
doc : "" ,
format : String ,
default : undefined ,
sensitive : true ,
skipGenerate : true ,
} ,
encryptionKey : {
doc : "" ,
format : String ,
default : undefined ,
sensitive : true ,
skipGenerate : true ,
} ,
google : {
id : {
doc : "reference https://next-auth.js.org/providers/google" ,
format : String ,
default : undefined ,
env : "GOOGLE_ID" ,
sensitive : true ,
} ,
secret : {
doc : "reference https://next-auth.js.org/providers/google" ,
format : String ,
default : undefined ,
env : "GOOGLE_SECRET" ,
sensitive : true ,
} ,
} ,
github : {
id : {
doc : "reference https://next-auth.js.org/providers/github" ,
format : String ,
default : undefined ,
env : "GITHUB_ID" ,
sensitive : true ,
} ,
secret : {
doc : "reference https://next-auth.js.org/providers/github" ,
format : String ,
default : undefined ,
env : "GITHUB_SECRET" ,
sensitive : true ,
} ,
} ,
gitlab : {
id : {
doc : "reference https://next-auth.js.org/providers/gitlab" ,
format : String ,
default : undefined ,
env : "GITLAB_ID" ,
sensitive : true ,
} ,
secret : {
doc : "reference https://next-auth.js.org/providers/gitlab" ,
format : String ,
default : undefined ,
env : "GITLAB_SECRET" ,
sensitive : true ,
} ,
} ,
cognito : {
id : {
doc : "reference https://next-auth.js.org/providers/cognito" ,
format : String ,
default : undefined ,
env : "COGNITO_ID" ,
sensitive : true ,
} ,
secret : {
doc : "reference https://next-auth.js.org/providers/cognito" ,
format : String ,
default : undefined ,
env : "COGNITO_SECRET" ,
sensitive : true ,
} ,
domain : {
doc : "reference https://next-auth.js.org/providers/cognito" ,
format : String ,
default : undefined ,
env : "COGNITO_DOMAIN" ,
sensitive : true ,
} ,
} ,
} ,
cfaccess : {
audience : {
doc : "the cloudflare access audience id" ,
format : String ,
default : undefined ,
env : "CFACCESS_AUDIENCE" ,
} ,
domain : {
doc : "the cloudflare access domain, something like `YOURAPP.cloudflareaccess.com`" ,
format : String ,
default : undefined ,
env : "CFACCESS_DOMAIN" ,
} ,
} ,
signald : {
enabled : {
doc : "Whether to enable the signald signal backend" ,
format : "Boolean" ,
default : false ,
env : "SIGNALD_ENABLED" ,
} ,
socket : {
doc : "the unix domain socket signald is listening on" ,
format : String ,
default : ` ${ process . cwd ( ) } /signald/signald.sock ` ,
env : "SIGNALD_SOCKET" ,
} ,
} ,
} ;
// define the interfaces for the concrete config objects
export interface IDBConfig {
connection : string ;
name : string ;
owner : string ;
}
export interface IWorkerConfig {
connection : string ;
concurrency : number ;
pollInterval : number ;
}
export interface IPostgraphileConfig {
auth : string ;
visitor : string ;
appRootConnection : string ;
authConnection : string ;
schema : string ;
enableGraphiql : boolean ;
}
export interface IDevConfig {
shadowConnection : string ;
rootConnection : string ;
}
export interface IFrontendConfig {
url : string ;
apiUrl : string ;
}
export interface INextAuthConfig {
secret : string ;
audience : string ;
signingKey : string ;
encryptionKey : string ;
signingKeyB64 : string ;
encryptionKeyB64 : string ;
google ? : { id : string ; secret : string } ;
github ? : { id : string ; secret : string } ;
gitlab ? : { id : string ; secret : string } ;
cognito ? : { id : string ; secret : string ; domain : string } ;
}
export interface ICFAccessConfig {
audience : string ;
domain : string ;
}
export interface ISignaldConifg {
enabled : boolean ;
socket : string ;
}
// Extend the metamigo base type to add your app's custom config along side the out
// of the box Metamigo config
export interface IAppConfig extends Metamigo . IMetamigoConfig {
db : IDBConfig ;
worker : IWorkerConfig ;
postgraphile : IPostgraphileConfig ;
dev : IDevConfig ;
frontend : IFrontendConfig ;
nextAuth : INextAuthConfig ;
cfaccess : ICFAccessConfig ;
signald : ISignaldConifg ;
}
export type IAppConvict = Metamigo . ExtendedConvict < IAppConfig > ;
// Merge the Metamigo base schema with your app's schmea
// @ts-ignore
export const schema : convict.Schema < IAppConfig > = {
. . . Metamigo . configBaseSchema ,
. . . configSchema ,
} ;
export const loadConfig = async ( ) : Promise < IAppConfig > = > {
const config = await Metamigo . loadConfiguration ( schema ) ;
if ( ! config . frontend . url || config . frontend . url === "" )
throw new Error (
"configuration value frontend.url is missing. Add to config or set NEXTAUTH_URL env var"
) ;
// nextauth expects the url to be provided with this environment variable, so we will munge it in place here
process . env . NEXTAUTH_URL = config . frontend . url ;
if ( config . nextAuth . signingKeyB64 )
config . nextAuth . signingKey = Buffer . from (
config . nextAuth . signingKeyB64 ,
"base64"
) . toString ( "utf-8" ) ;
if ( config . nextAuth . encryptionKeyB64 )
config . nextAuth . encryptionKey = Buffer . from (
config . nextAuth . encryptionKeyB64 ,
"base64"
) . toString ( "utf-8" ) ;
if ( ! config . nextAuth . audience || config . nextAuth . audience === "" )
config . nextAuth . audience = config . frontend . url ;
return config as any ;
} ;
export const loadConfigRaw = async ( ) : Promise < IAppConvict > = > {
return Metamigo . loadConfigurationRaw ( schema ) ;
} ;
const config = defState ( "config" , {
start : loadConfig ,
} ) ;
export default config ;