Unified · Split
| @@ -31,7 +31,7 @@ import { CloudAuthHandlers, CloudAuthPublicHandlers } from "./auth/handlers"; · 30 unmodified lines | ||
| 31 | 31 | import { WorkOSAuth } from "./auth/workos"; |
| 32 | 32 | import { DbService } from "./services/db"; |
| 33 | 33 | import { createTeamExecutor } from "./services/executor"; |
| 34 | −import { env } from "./env"; | |
| 34 | +import { server } from "./env"; | |
| 35 | 35 | |
| 36 | 36 | const ProtectedCloudApi = addGroup(OpenApiGroup) |
| 37 | 37 | .add(McpGroup) |
| @@ -105,7 +105,7 @@ const COOKIE_OPTIONS = { · 67 unmodified lines | ||
| 105 | 105 | httpOnly: true, |
| 106 | 106 | sameSite: "lax" as const, |
| 107 | 107 | maxAge: 60 * 60 * 24 * 7, |
| 108 | − secure: env.NODE_ENV === "production", | |
| 108 | + secure: server.NODE_ENV === "production", | |
| 109 | 109 | }; |
| 110 | 110 | |
| 111 | 111 | const resolveAuth = (request: Request) => |
| @@ -152,7 +152,7 @@ const resolveExecutor = (teamId: string) => · 40 unmodified lines | ||
| 152 | 152 | const users = yield* UserStoreService; |
| 153 | 153 | const team = yield* users.use((store) => store.getTeam(teamId)); |
| 154 | 154 | const teamName = team?.name ?? "Unknown Team"; |
| 155 | − const encryptionKey = env.ENCRYPTION_KEY; | |
| 155 | + const encryptionKey = server.ENCRYPTION_KEY; | |
| 156 | 156 | return yield* createTeamExecutor(teamId, teamName, encryptionKey); |
| 157 | 157 | }); |
| 158 | 158 | |
| @@ -6,14 +6,14 @@ import { addGroup } from "@executor/api"; · 5 unmodified lines | ||
| 6 | 6 | import { AUTH_PATHS, CloudAuthApi, CloudAuthPublicApi } from "./api"; |
| 7 | 7 | import { AuthContext, UserStoreService } from "./context"; |
| 8 | 8 | import { WorkOSAuth } from "./workos"; |
| 9 | −import { env } from "../env"; | |
| 9 | +import { server } from "../env"; | |
| 10 | 10 | |
| 11 | 11 | const COOKIE_OPTIONS = { |
| 12 | 12 | path: "/", |
| 13 | 13 | httpOnly: true, |
| 14 | 14 | sameSite: "lax" as const, |
| 15 | 15 | maxAge: 60 * 60 * 24 * 7, |
| 16 | − secure: env.NODE_ENV === "production", | |
| 16 | + secure: server.NODE_ENV === "production", | |
| 17 | 17 | }; |
| 18 | 18 | |
| 19 | 19 | // --------------------------------------------------------------------------- |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | import { Context, Effect, Layer } from "effect"; |
| 6 | 6 | import { WorkOS } from "@workos-inc/node"; |
| 7 | 7 | import { WorkOSError } from "./errors"; |
| 8 | −import { env } from "../env"; | |
| 8 | +import { server } from "../env"; | |
| 9 | 9 | |
| 10 | 10 | const COOKIE_NAME = "wos-session"; |
| 11 | 11 | |
| @@ -15,9 +15,9 @@ const COOKIE_NAME = "wos-session"; · 3 unmodified lines | ||
| 15 | 15 | |
| 16 | 16 | |
| 17 | 17 | const make = Effect.gen(function* () { |
| 18 | − const apiKey = env.WORKOS_API_KEY; | |
| 19 | − const clientId = env.WORKOS_CLIENT_ID; | |
| 20 | − const cookiePassword = env.WORKOS_COOKIE_PASSWORD; | |
| 18 | + const apiKey = server.WORKOS_API_KEY; | |
| 19 | + const clientId = server.WORKOS_CLIENT_ID; | |
| 20 | + const cookiePassword = server.WORKOS_COOKIE_PASSWORD; | |
| 21 | 21 | |
| 22 | 22 | if (!cookiePassword || cookiePassword.length < 32) { |
| 23 | 23 | return yield* Effect.die(new Error("WORKOS_COOKIE_PASSWORD must be at least 32 characters")); |
| @@ -1,6 +1,6 @@ | ||
| 1 | 1 | import { createEnv, Env } from "@executor/env"; |
| 2 | 2 | |
| 3 | −const server = { | |
| 3 | +const sharedShape = { | |
| 4 | 4 | NODE_ENV: Env.literalOr( |
| 5 | 5 | "NODE_ENV", |
| 6 | 6 | "development", |
| @@ -8,6 +8,9 @@ const server = { · 1 unmodified line | ||
| 8 | 8 | "test", |
| 9 | 9 | "production", |
| 10 | 10 | ), |
| 11 | +}; | |
| 12 | + | |
| 13 | +const serverShape = { | |
| 11 | 14 | DATABASE_URL: Env.stringOr("DATABASE_URL", ""), |
| 12 | 15 | PGLITE_DATA_DIR: Env.stringOr("PGLITE_DATA_DIR", ".pglite"), |
| 13 | 16 | ENCRYPTION_KEY: Env.stringOr( |
| @@ -19,8 +22,11 @@ const server = { · 5 unmodified lines | ||
| 19 | 22 | WORKOS_COOKIE_PASSWORD: Env.string("WORKOS_COOKIE_PASSWORD"), |
| 20 | 23 | }; |
| 21 | 24 | |
| 22 | −type CloudEnv = Readonly<{ | |
| 25 | +type SharedEnv = Readonly<{ | |
| 23 | 26 | NODE_ENV: "development" | "test" | "production"; |
| 27 | +}>; | |
| 28 | + | |
| 29 | +type ServerEnv = SharedEnv & Readonly<{ | |
| 24 | 30 | DATABASE_URL: string; |
| 25 | 31 | PGLITE_DATA_DIR: string; |
| 26 | 32 | ENCRYPTION_KEY: string; |
| @@ -29,8 +35,24 @@ type CloudEnv = Readonly<{ · 2 unmodified lines | ||
| 29 | 35 | WORKOS_COOKIE_PASSWORD: string; |
| 30 | 36 | }>; |
| 31 | 37 | |
| 32 | −export const env = createEnv<undefined, typeof server>({ | |
| 33 | − server, | |
| 38 | +type WebEnv = Readonly<Record<string, never>>; | |
| 39 | + | |
| 40 | +export const shared = createEnv({ | |
| 41 | + server: sharedShape, | |
| 42 | + runtimeEnv: process.env, | |
| 43 | + emptyStringAsUndefined: true, | |
| 44 | +}) as SharedEnv; | |
| 45 | + | |
| 46 | +export const web = createEnv({ | |
| 47 | + clientPrefix: "PUBLIC_", | |
| 48 | + client: {}, | |
| 49 | + runtimeEnv: process.env, | |
| 50 | + emptyStringAsUndefined: true, | |
| 51 | +}) as WebEnv; | |
| 52 | + | |
| 53 | +export const server = createEnv({ | |
| 54 | + server: serverShape, | |
| 55 | + extends: [shared], | |
| 34 | 56 | runtimeEnv: process.env, |
| 35 | 57 | emptyStringAsUndefined: true, |
| 36 | −}) as CloudEnv; | |
| 58 | +}) as ServerEnv; | |
| @@ -7,7 +7,7 @@ import { resolve } from "node:path"; · 6 unmodified lines | ||
| 7 | 7 | import * as sharedSchema from "@executor/storage-postgres/schema"; |
| 8 | 8 | import * as cloudSchema from "./schema"; |
| 9 | 9 | import type { DrizzleDb } from "@executor/storage-postgres"; |
| 10 | −import { env } from "../env"; | |
| 10 | +import { server } from "../env"; | |
| 11 | 11 | |
| 12 | 12 | const schema = { ...sharedSchema, ...cloudSchema }; |
| 13 | 13 | |
| @@ -24,11 +24,11 @@ type DbResource = { · 10 unmodified lines | ||
| 24 | 24 | }; |
| 25 | 25 | |
| 26 | 26 | const createDbResource = async (): Promise<DbResource> => { |
| 27 | − if (env.DATABASE_URL) { | |
| 27 | + if (server.DATABASE_URL) { | |
| 28 | 28 | const { drizzle } = await import("drizzle-orm/node-postgres"); |
| 29 | 29 | const { migrate } = await import("drizzle-orm/node-postgres/migrator"); |
| 30 | 30 | const { Pool } = await import("pg"); |
| 31 | − const pool = new Pool({ connectionString: env.DATABASE_URL }); | |
| 31 | + const pool = new Pool({ connectionString: server.DATABASE_URL }); | |
| 32 | 32 | const db = drizzle(pool, { schema }) as DrizzleDb; |
| 33 | 33 | await migrate(db as any, { migrationsFolder: MIGRATIONS_DIR }); |
| 34 | 34 | return { |
| @@ -40,7 +40,7 @@ const createDbResource = async (): Promise<DbResource> => { · 5 unmodified lines | ||
| 40 | 40 | const { PGlite } = await import("@electric-sql/pglite"); |
| 41 | 41 | const { drizzle } = await import("drizzle-orm/pglite"); |
| 42 | 42 | const { migrate } = await import("drizzle-orm/pglite/migrator"); |
| 43 | − const dataDir = env.PGLITE_DATA_DIR; | |
| 43 | + const dataDir = server.PGLITE_DATA_DIR; | |
| 44 | 44 | const client = new PGlite(dataDir); |
| 45 | 45 | const db = drizzle(client, { schema }) as DrizzleDb; |
| 46 | 46 | await migrate(db, { migrationsFolder: MIGRATIONS_DIR }); |