Skip to content

Commit e94fa74

Browse files
committed
use varlock ENV
- remove extra getEnv() + global ENV logic - use ENV from varlock/env instead of process.env - remove extra coercion/validation - add MODE to schema (we should merge this with NODE_ENV)
1 parent 4daf8c8 commit e94fa74

33 files changed

+125
-135
lines changed

.env.schema

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
# @type=enum(development, production, test)
99
NODE_ENV=development
10+
# @type=enum(development, production, test)
11+
MODE=$NODE_ENV
1012

1113
# @type=port
1214
PORT=3000

app/entry.client.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { startTransition } from 'react'
22
import { hydrateRoot } from 'react-dom/client'
33
import { HydratedRouter } from 'react-router/dom'
4+
import { ENV } from 'varlock/env'
45

56
if (ENV.MODE === 'production' && ENV.SENTRY_DSN) {
67
void import('./utils/monitoring.client.tsx').then(({ init }) => init())

app/entry.server.tsx

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,29 +12,26 @@ import {
1212
type ActionFunctionArgs,
1313
type HandleDocumentRequestFunction,
1414
} from 'react-router'
15-
import { getEnv } from './utils/env.server.ts'
15+
import { ENV } from 'varlock/env'
1616
import { getInstanceInfo } from './utils/litefs.server.ts'
1717
import { NonceProvider } from './utils/nonce-provider.ts'
1818
import { makeTimings } from './utils/timing.server.ts'
1919

2020
export const streamTimeout = 5000
2121

22-
global.ENV = getEnv()
23-
24-
const MODE = process.env.NODE_ENV
2522

2623
type DocRequestArgs = Parameters<HandleDocumentRequestFunction>
2724

2825
export default async function handleRequest(...args: DocRequestArgs) {
2926
const [request, responseStatusCode, responseHeaders, reactRouterContext] =
3027
args
3128
const { currentInstance, primaryInstance } = await getInstanceInfo()
32-
responseHeaders.set('fly-region', process.env.FLY_REGION ?? 'unknown')
33-
responseHeaders.set('fly-app', process.env.FLY_APP_NAME ?? 'unknown')
29+
responseHeaders.set('fly-region', ENV.FLY_REGION ?? 'unknown')
30+
responseHeaders.set('fly-app', ENV.FLY_APP_NAME ?? 'unknown')
3431
responseHeaders.set('fly-primary-instance', primaryInstance)
3532
responseHeaders.set('fly-instance', currentInstance)
3633

37-
if (process.env.NODE_ENV === 'production' && process.env.SENTRY_DSN) {
34+
if (ENV.NODE_ENV === 'production' && ENV.SENTRY_DSN) {
3835
responseHeaders.append('Document-Policy', 'js-profiling')
3936
}
4037

@@ -71,8 +68,8 @@ export default async function handleRequest(...args: DocRequestArgs) {
7168
directives: {
7269
fetch: {
7370
'connect-src': [
74-
MODE === 'development' ? 'ws:' : undefined,
75-
process.env.SENTRY_DSN ? '*.sentry.io' : undefined,
71+
ENV.MODE === 'development' ? 'ws:' : undefined,
72+
ENV.SENTRY_DSN ? '*.sentry.io' : undefined,
7673
"'self'",
7774
],
7875
'font-src': ["'self'"],
@@ -113,8 +110,8 @@ export default async function handleRequest(...args: DocRequestArgs) {
113110

114111
export async function handleDataRequest(response: Response) {
115112
const { currentInstance, primaryInstance } = await getInstanceInfo()
116-
response.headers.set('fly-region', process.env.FLY_REGION ?? 'unknown')
117-
response.headers.set('fly-app', process.env.FLY_APP_NAME ?? 'unknown')
113+
response.headers.set('fly-region', ENV.FLY_REGION ?? 'unknown')
114+
response.headers.set('fly-app', ENV.FLY_APP_NAME ?? 'unknown')
118115
response.headers.set('fly-primary-instance', primaryInstance)
119116
response.headers.set('fly-instance', currentInstance)
120117

app/root.tsx

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
useMatches,
1212
} from 'react-router'
1313
import { HoneypotProvider } from 'remix-utils/honeypot/react'
14+
import { ENV } from 'varlock/env'
1415
import { type Route } from './+types/root.ts'
1516
import appleTouchIconAssetUrl from './assets/favicons/apple-touch-icon.png'
1617
import faviconAssetUrl from './assets/favicons/favicon.svg'
@@ -31,7 +32,6 @@ import tailwindStyleSheetUrl from './styles/tailwind.css?url'
3132
import { getUserId, logout } from './utils/auth.server.ts'
3233
import { ClientHintCheck, getHints } from './utils/client-hints.tsx'
3334
import { prisma } from './utils/db.server.ts'
34-
import { getEnv } from './utils/env.server.ts'
3535
import { pipeHeaders } from './utils/headers.server.ts'
3636
import { honeypot } from './utils/honeypot.server.ts'
3737
import { combineHeaders, getDomainUrl, getImgSrc } from './utils/misc.tsx'
@@ -119,7 +119,6 @@ export async function loader({ request }: Route.LoaderArgs) {
119119
theme: getTheme(request),
120120
},
121121
},
122-
ENV: getEnv(),
123122
toast,
124123
honeyProps,
125124
},
@@ -138,34 +137,25 @@ function Document({
138137
children,
139138
nonce,
140139
theme = 'light',
141-
env = {},
142140
}: {
143141
children: React.ReactNode
144142
nonce: string
145143
theme?: Theme
146-
env?: Record<string, string | undefined>
147144
}) {
148-
const allowIndexing = ENV.ALLOW_INDEXING !== 'false'
149145
return (
150146
<html lang="en" className={`${theme} h-full overflow-x-hidden`}>
151147
<head>
152148
<ClientHintCheck nonce={nonce} />
153149
<Meta />
154150
<meta charSet="utf-8" />
155151
<meta name="viewport" content="width=device-width,initial-scale=1" />
156-
{allowIndexing ? null : (
152+
{ENV.ALLOW_INDEXING ? null : (
157153
<meta name="robots" content="noindex, nofollow" />
158154
)}
159155
<Links />
160156
</head>
161157
<body className="bg-background text-foreground">
162158
{children}
163-
<script
164-
nonce={nonce}
165-
dangerouslySetInnerHTML={{
166-
__html: `window.ENV = ${JSON.stringify(env)}`,
167-
}}
168-
/>
169159
<ScrollRestoration nonce={nonce} />
170160
<Scripts nonce={nonce} />
171161
</body>
@@ -174,12 +164,10 @@ function Document({
174164
}
175165

176166
export function Layout({ children }: { children: React.ReactNode }) {
177-
// if there was an error running the loader, data could be missing
178-
const data = useLoaderData<typeof loader | null>()
179167
const nonce = useNonce()
180168
const theme = useOptionalTheme()
181169
return (
182-
<Document nonce={nonce} theme={theme} env={data?.ENV}>
170+
<Document nonce={nonce} theme={theme}>
183171
{children}
184172
</Document>
185173
)

app/routes/_auth/auth.$provider/callback.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { invariant } from '@epic-web/invariant'
22
import { faker } from '@faker-js/faker'
33
import { SetCookie } from '@mjackson/headers'
44
import { http } from 'msw'
5+
import { ENV } from 'varlock/env'
56
import { afterEach, expect, test } from 'vitest'
67
import { twoFAVerificationType } from '#app/routes/settings/profile/two-factor/_layout.tsx'
78
import { getSessionExpirationDate, sessionKey } from '#app/utils/auth.server.ts'
@@ -231,7 +232,7 @@ async function setupRequest({
231232
sameSite: 'Lax',
232233
httpOnly: true,
233234
maxAge: 60 * 10,
234-
secure: process.env.NODE_ENV === 'production' || undefined,
235+
secure: ENV.NODE_ENV === 'production' || undefined,
235236
})
236237
const request = new Request(url.toString(), {
237238
method: 'GET',

app/routes/_auth/webauthn/utils.server.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
type RegistrationResponseJSON,
44
} from '@simplewebauthn/server'
55
import { createCookie } from 'react-router'
6+
import { ENV } from 'varlock/env'
67
import { z } from 'zod'
78
import { getDomainUrl } from '#app/utils/misc.tsx'
89

@@ -11,8 +12,8 @@ export const passkeyCookie = createCookie('webauthn-challenge', {
1112
sameSite: 'lax',
1213
httpOnly: true,
1314
maxAge: 60 * 60 * 2,
14-
secure: process.env.NODE_ENV === 'production',
15-
secrets: [process.env.SESSION_SECRET],
15+
secure: ENV.NODE_ENV === 'production',
16+
secrets: [ENV.SESSION_SECRET],
1617
})
1718

1819
export const PasskeyCookieSchema = z.object({

app/routes/admin/cache/sqlite.server.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { redirect } from 'react-router'
2+
import { ENV } from 'varlock/env'
23
import { z } from 'zod'
34
import { cache } from '#app/utils/cache.server.ts'
45
import {
@@ -21,7 +22,7 @@ export async function updatePrimaryCacheValue({
2122
)
2223
}
2324
const domain = getInternalInstanceDomain(primaryInstance)
24-
const token = process.env.INTERNAL_COMMAND_TOKEN
25+
const token = ENV.INTERNAL_COMMAND_TOKEN
2526
return fetch(`${domain}/admin/cache/sqlite`, {
2627
method: 'POST',
2728
headers: {
@@ -39,7 +40,7 @@ export async function action({ request }: Route.ActionArgs) {
3940
`${request.url} should only be called on the primary instance (${primaryInstance})}`,
4041
)
4142
}
42-
const token = process.env.INTERNAL_COMMAND_TOKEN
43+
const token = ENV.INTERNAL_COMMAND_TOKEN
4344
const isAuthorized =
4445
request.headers.get('Authorization') === `Bearer ${token}`
4546
if (!isAuthorized) {

app/routes/resources/images.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { promises as fs, constants } from 'node:fs'
22
import { invariantResponse } from '@epic-web/invariant'
33
import { getImgResponse } from 'openimg/node'
4+
import { ENV } from 'varlock/env'
45
import { getDomainUrl } from '#app/utils/misc.tsx'
56
import { getSignedGetRequestInfo } from '#app/utils/storage.server.ts'
67
import { type Route } from './+types/images'
@@ -11,7 +12,7 @@ async function getCacheDir() {
1112
if (cacheDir) return cacheDir
1213

1314
let dir = './tests/fixtures/openimg'
14-
if (process.env.NODE_ENV === 'production') {
15+
if (ENV.NODE_ENV === 'production') {
1516
const isAccessible = await fs
1617
.access('/data', constants.W_OK)
1718
.then(() => true)
@@ -38,7 +39,7 @@ export async function loader({ request }: Route.LoaderArgs) {
3839
headers,
3940
allowlistedOrigins: [
4041
getDomainUrl(request),
41-
process.env.AWS_ENDPOINT_URL_S3,
42+
ENV.AWS_ENDPOINT_URL_S3,
4243
].filter(Boolean),
4344
cacheFolder: await getCacheDir(),
4445
getImgSource: () => {

app/utils/cache.server.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@ import {
1414
} from '@epic-web/cachified'
1515
import { remember } from '@epic-web/remember'
1616
import { LRUCache } from 'lru-cache'
17+
import { ENV } from 'varlock/env'
1718
import { z } from 'zod'
1819
import { updatePrimaryCacheValue } from '#app/routes/admin/cache/sqlite.server.ts'
1920
import { getInstanceInfo, getInstanceInfoSync } from './litefs.server.ts'
2021
import { cachifiedTimingReporter, type Timings } from './timing.server.ts'
2122

22-
const CACHE_DATABASE_PATH = process.env.CACHE_DATABASE_PATH
23+
const CACHE_DATABASE_PATH = ENV.CACHE_DATABASE_PATH
2324

2425
const cacheDb = remember('cacheDb', createDatabase)
2526

app/utils/email.server.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { render } from '@react-email/components'
22
import { type ReactElement } from 'react'
3+
import { ENV } from 'varlock/env'
34
import { z } from 'zod'
45

56
const resendErrorSchema = z.union([
@@ -40,7 +41,7 @@ export async function sendEmail({
4041
}
4142

4243
// feel free to remove this condition once you've set up resend
43-
if (!process.env.RESEND_API_KEY && !process.env.MOCKS) {
44+
if (!ENV.RESEND_API_KEY && !ENV.MOCKS) {
4445
console.error(`RESEND_API_KEY not set and we're not in mocks mode.`)
4546
console.error(
4647
`To send emails, set the RESEND_API_KEY environment variable.`,
@@ -56,7 +57,7 @@ export async function sendEmail({
5657
method: 'POST',
5758
body: JSON.stringify(email),
5859
headers: {
59-
Authorization: `Bearer ${process.env.RESEND_API_KEY}`,
60+
Authorization: `Bearer ${ENV.RESEND_API_KEY}`,
6061
'Content-Type': 'application/json',
6162
},
6263
})

0 commit comments

Comments
 (0)