Skip to content

Commit

Permalink
feat: check definition of config variables at runtime (#12)
Browse files Browse the repository at this point in the history
* feat: check definition of config variables at runtime

* ci(server): fix Dockerfile
  • Loading branch information
sripwoud committed Oct 11, 2024
1 parent 47ed437 commit 9d3c8bb
Show file tree
Hide file tree
Showing 24 changed files with 124 additions and 43 deletions.
8 changes: 6 additions & 2 deletions .envrc.example
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use asdf

# db
export SUPABASE_URL=
export SUPABASE_ANON_KEY=

export LOCAL_SUPABASE_URL=
export LOCAL_SUPABASE_ANON_KEY=
# server
export ALCHEMY_API_KEY=

# client
export NEXT_PUBLIC_SERVER_URL=
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ lcov.info
.envrc
**/*.bak
repopack-output.txt
*.tsbuildinfo
9 changes: 7 additions & 2 deletions .lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ pre-commit:
stage_fixed: true
lint:
run: bun biome lint --config-path=.biome.jsonc --no-errors-on-unmatched
typecheck:
typecheck-client:
glob: "*.{cjs,js,jsx,mjs,ts,tsx}"
run: bun tsc-files --noEmit
root: "apps/client"
run: bun tsc-files --noEmit {staged_files}
typecheck-server:
glob: "*.{cjs,js,jsx,mjs,ts,tsx}"
root: "apps/server"
run: bun tsc-files --noEmit {staged_files}
5 changes: 2 additions & 3 deletions apps/client/src/lib/account-kit.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { alchemy, sepolia } from '@account-kit/infra'
import { type AlchemyAccountsUIConfig, cookieStorage, createConfig } from '@account-kit/react'
import { url } from 'client/l/trpc'
import config from 'client/l/config'

console.log(url)
const uiConfig: AlchemyAccountsUIConfig = {
illustrationStyle: 'filled',
auth: {
Expand All @@ -18,6 +17,6 @@ export const alchemyConfig = createConfig({
storage: cookieStorage,
transport: alchemy({
// proxying to backend server to hide API key
rpcUrl: `${url}/web3-rpc-proxy`,
rpcUrl: `${config.serverUrl}/${config.alchemyProxyEndpoint}`,
}),
}, uiConfig)
16 changes: 16 additions & 0 deletions apps/client/src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { isEnvVarDefined, sharedConfig, type SharedConfigI } from 'config'

interface ClientConfigI {
serverUrl: string
}

// @ts-expect-error 4111
const serverUrl = process.env.NEXT_PUBLIC_SERVER_URL ?? ''
isEnvVarDefined(serverUrl, 'NEXT_PUBLIC_SERVER_URL')

const clientConfig: SharedConfigI & ClientConfigI = {
...sharedConfig,
serverUrl,
}

export default clientConfig
8 changes: 2 additions & 6 deletions apps/client/src/lib/trpc.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
import { createTRPCProxyClient, httpBatchLink, type HTTPHeaders } from '@trpc/client'
import config from 'client/l/config'
import type { AppRouter } from 'server/trpc/trpc.router'

// TODO: make this configurable and/or use env vars
const PORT = 3001
const PROD_URL = 'https://rideau.fly.dev'
export const url = process.env.NODE_ENV === 'production' ? PROD_URL : `http://localhost:${PORT}`

let headers: HTTPHeaders

export const setHeaders = (newHeaders: HTTPHeaders) => {
Expand All @@ -16,7 +12,7 @@ export const trpc = createTRPCProxyClient<AppRouter>({
links: [
httpBatchLink({
headers: () => headers,
url: `${url}/trpc`,
url: `${config.serverUrl}/trpc`,
}),
],
})
3 changes: 2 additions & 1 deletion apps/server/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ RUN yarn install --ignore-scripts --frozen-lockfile --production=false
FROM install AS prerelease
COPY tsconfig.json .
COPY apps/server apps/server
COPY config config
RUN yarn workspace server build &&\
find -type d -name node_modules -exec rm -fr {} + &&\
yarn install --frozen-lockfile --production=true
Expand All @@ -27,4 +28,4 @@ USER node
# TODO: make this configurable/overridable
EXPOSE 3001
ENTRYPOINT ["dumb-init", "--"]
CMD ["node", "apps/server/dist"]
CMD ["node", "apps/server/dist/apps/server/src/index"]
Empty file added apps/server/config.ts
Empty file.
2 changes: 1 addition & 1 deletion apps/server/fly.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#

app = 'rideau'
primary_region = 'ams'
primary_region = 'fra'

[build]

Expand Down
2 changes: 1 addition & 1 deletion apps/server/nest-cli.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/nest-cli",
"collection": "@nestjs/schematics",
"entryFile": "index",
"entryFile": "apps/server/src/index",
"compilerOptions": {
"deleteOutDir": true
}
Expand Down
2 changes: 1 addition & 1 deletion apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"@nestjs/testing": "^10.0.0",
"@types/express": "^5.0.0",
"@types/jest": "^29.5.2",
"@types/node": "^20.3.1",
"@types/node": "^22.7.5",
"@types/supertest": "^6.0.0",
"eslint": "^8.42.0",
"jest": "^29.5.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { All, Controller, Logger, Req, Res } from '@nestjs/common'
import type { Request, Response } from 'express'
import config from 'server/l/config'

const ENDPOINT = 'web3-rpc-proxy'
const endpointRgx = new RegExp(`^/${ENDPOINT}/`)
const endpointRgx = new RegExp(`^/${config.alchemyProxyEndpoint}/`)
const API_URL = 'https://api.g.alchemy.com'

@Controller(ENDPOINT)
export class Web3RpcProxyController {
private readonly logger = new Logger(Web3RpcProxyController.name)
@Controller(config.alchemyProxyEndpoint)
export class AlchemyProxyController {
private readonly logger = new Logger(AlchemyProxyController.name)

@All('*')
async proxy(@Req() req: Request, @Res() res: Response) {
Expand All @@ -31,7 +31,7 @@ export class Web3RpcProxyController {
method,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env['ALCHEMY_API_KEY']}`,
Authorization: `Bearer ${config.alchemyApiKey}`,
},
body: JSON.stringify(body),
},
Expand Down
4 changes: 2 additions & 2 deletions apps/server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import { Module } from '@nestjs/common'
import { AppController } from 'server/app.controller'
import { AppService } from 'server/app.service'
import { TrpcModule } from 'server/trpc/trpc.module'
import { Web3RpcProxyController } from './web3-rpc-proxy/web3-rpc-proxy.controller'
import { AlchemyProxyController } from './alchemy-proxy/alchemy-proxy.controller'

@Module({
imports: [TrpcModule],
controllers: [AppController, Web3RpcProxyController],
controllers: [AppController, AlchemyProxyController],
providers: [AppService],
})
export class AppModule {}
6 changes: 2 additions & 4 deletions apps/server/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { NestFactory } from '@nestjs/core'
import { AppModule } from 'server/app.module'
import config from 'server/l/config'
import { TrpcRouter } from 'server/trpc/trpc.router'

// TODO: make port configurable
const PORT = 3001

async function bootstrap() {
const app = await NestFactory.create(AppModule)
app.enableCors()

const trpc = app.get(TrpcRouter)
trpc.applyMiddleware(app)

await app.listen(PORT)
await app.listen(config.port)
}

bootstrap()
19 changes: 19 additions & 0 deletions apps/server/src/lib/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { getEnvVar, sharedConfig, type SharedConfigI } from 'config'

interface ServerConfigI {
alchemyApiKey: string
port: number
supabase: { anonKey: string; url: string }
}

const serverConfig: ServerConfigI & SharedConfigI = {
...sharedConfig,
alchemyApiKey: getEnvVar('ALCHEMY_API_KEY'),
port: 3001,
supabase: {
anonKey: getEnvVar('SUPABASE_ANON_KEY'),
url: getEnvVar('SUPABASE_URL'),
},
}

export default serverConfig
4 changes: 2 additions & 2 deletions apps/server/src/supabase/supabase.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Injectable } from '@nestjs/common'
import { createClient } from '@supabase/supabase-js'
import config from 'server/l/config'

@Injectable()
export class SupabaseService {
// biome-ignore lint/style/noNonNullAssertion: FIXME
supabase = createClient(process.env['SUPABASE_URL']!, process.env['SUPABASE_ANON_KEY']!)
supabase = createClient(config.supabase.url, config.supabase.anonKey)
}
Binary file modified bun.lockb
Binary file not shown.
3 changes: 3 additions & 0 deletions config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export { default as sharedConfig } from 'config/shared'
export type { SharedConfigI } from 'config/types'
export { getEnvVar, isEnvVarDefined } from 'config/utils'
8 changes: 8 additions & 0 deletions config/shared.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { SharedConfigI } from 'config/types'

const config: SharedConfigI = {
appName: 'rideau',
alchemyProxyEndpoint: 'alchemy',
}

export default config
9 changes: 9 additions & 0 deletions config/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export enum Env {
DEVELOPMENT = 'DEVELOPMENT',
PRODUCTION = 'PRODUCTION',
}

export interface SharedConfigI {
appName: string
alchemyProxyEndpoint: string
}
15 changes: 15 additions & 0 deletions config/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export function isEnvVarDefined(name: string, value: unknown) {
if (value === '') throw new Error(`Missing environment variable ${name}`)
}

/**
* DO NOT USE TO CHECK ENVIRONMENT VARIABLES USED CLIENT SIDE IN NEXTJS
* NextJS inline client-side environment variables to make them accessible by the browser
* But dynamic access to environment variables is not inlined
* {@link https://nextjs.org/docs/basic-features/environment-variables#loading-environment-variables}
*/
export function getEnvVar<T extends string>(name: T) {
const value = process.env[name] ?? ''
isEnvVarDefined(name, value)
return value
}
18 changes: 9 additions & 9 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"noEmit": true,
"baseUrl": "apps",
"baseUrl": ".",
"allowJs": true,
"checkJs": true,
"declaration": true,
Expand All @@ -20,14 +20,14 @@
"noUnusedLocals": true,
"noUnusedParameters": true,
"paths": {
"client/*": ["client/src/*"],
"client/c/*": ["client/src/components/*"],
"client/h/*": ["client/src/hooks/*"],
"client/l/*": ["client/src/lib/*"],
"client/p/*": ["client/src/providers/*"],
"client/p": ["client/src/providers"],
"server/*": ["server/src/*"],
"server/l/*": ["server/src/lib/*"]
"client/*": ["apps/client/src/*"],
"client/c/*": ["apps/client/src/components/*"],
"client/h/*": ["apps/client/src/hooks/*"],
"client/l/*": ["apps/client/src/lib/*"],
"client/p/*": ["apps/client/src/providers/*"],
"client/p": ["apps/client/src/providers"],
"server/*": ["apps/server/src/*"],
"server/l/*": ["apps/server/src/lib/*"]
},
"removeComments": true,
"skipDefaultLibCheck": true,
Expand Down
13 changes: 10 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
# bun ./bun.lockb --hash: FBCD7AF1034998C3-81b4157dbd3990ad-191C33EDCCA73559-4e08cd2f2985cf67
# bun ./bun.lockb --hash: A7975FC6190E722F-cfa64adf9c1f0f32-47EE7DF9252DAE90-f880c665a4692a26


"@aa-sdk/core@^4.0.0-beta.9":
Expand Down Expand Up @@ -3862,13 +3862,20 @@
dependencies:
undici-types "~5.26.4"

"@types/node@*", "@types/node@^20", "@types/node@^20.3.1":
"@types/node@*", "@types/node@^20":
version "20.16.10"
resolved "https://registry.npmjs.org/@types/node/-/node-20.16.10.tgz"
integrity sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==
dependencies:
undici-types "~6.19.2"

"@types/node@^22.7.5":
version "22.7.5"
resolved "https://registry.npmjs.org/@types/node/-/node-22.7.5.tgz"
integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==
dependencies:
undici-types "~6.19.2"

"@types/node-forge@^1.3.0":
version "1.3.11"
resolved "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz"
Expand Down Expand Up @@ -10173,7 +10180,7 @@ [email protected], serve-static@^1.13.1:
"@nestjs/testing" "^10.0.0"
"@types/express" "^5.0.0"
"@types/jest" "^29.5.2"
"@types/node" "^20.3.1"
"@types/node" "^22.7.5"
"@types/supertest" "^6.0.0"
eslint "^8.42.0"
jest "^29.5.0"
Expand Down

0 comments on commit 9d3c8bb

Please sign in to comment.