History

refactor(cloud): export shared web and server env

Rhys Sullivan committed 7 months ago

Commit d3fede21 parent 9c5e8bf5 files · +40 −18Browse files

Unified · Split

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