Skip to content

Commit

Permalink
feat: add env vars for v5 UUID namespace and others
Browse files Browse the repository at this point in the history
Env-var typings on `process.env` have also been explicitly set to `string | undefined` to satisfy TS.
  • Loading branch information
trevor-anderson committed Jun 23, 2024
1 parent 4e72dc1 commit d2cfd4d
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 41 deletions.
9 changes: 6 additions & 3 deletions src/server/env/__mocks__/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { createEnvObject } from "../helpers.js";

const {
npm_package_version,
NODE_ENV = "test",
// SERVER
VITE_PROTOCOL: PROTOCOL = "http",
VITE_DOMAIN: DOMAIN = "localhost",
Expand All @@ -17,6 +16,7 @@ const {
VITE_WEB_CLIENT_URL: WEB_CLIENT_URL = "http://localhost:3000",
// AWS
VITE_AWS_REGION: AWS_REGION = "local",
VITE_DYNAMODB_REGION: DYNAMODB_REGION = "local",
VITE_DYNAMODB_TABLE_NAME: DYNAMODB_TABLE_NAME = "fixit-db-test",
VITE_DYNAMODB_ENDPOINT: DYNAMODB_ENDPOINT = "http://localhost:8000",
VITE_PINPOINT_PROJECT_ID: PINPOINT_PROJECT_ID = "TestTestTest",
Expand All @@ -27,8 +27,9 @@ const {
VITE_JWT_ISSUER: JWT_ISSUER = "TestTestTest",
VITE_JWT_EXPIRES_IN: JWT_EXPIRES_IN = "5m",
VITE_BCRYPT_SALT_ROUNDS: BCRYPT_SALT_ROUNDS = "10",
VITE_UUID_NAMESPACE: UUID_NAMESPACE = "aaaaaaaa-aaaa-5aaa-8aaa-aaaaaaaaaaaa", // 5=version, 8=variant
// SENTRY
VITE_SENTRY_DSN: SENTRY_DSN = "TestTestTest",
VITE_SENTRY_DSN: SENTRY_DSN,
// STRIPE
VITE_STRIPE_API_VERSION: STRIPE_API_VERSION = "2022-08-01",
VITE_STRIPE_PUBLISHABLE_KEY: STRIPE_PUBLISHABLE_KEY = "pk_fake_TestTestTest",
Expand All @@ -41,12 +42,13 @@ const {

export const ENV = createEnvObject({
...(!!npm_package_version && { npm_package_version }),
NODE_ENV,
NODE_ENV: "test",
PROTOCOL,
DOMAIN,
PORT,
WEB_CLIENT_URL,
AWS_REGION,
DYNAMODB_REGION,
DYNAMODB_TABLE_NAME,
DYNAMODB_ENDPOINT,
PINPOINT_PROJECT_ID,
Expand All @@ -56,6 +58,7 @@ export const ENV = createEnvObject({
JWT_ISSUER,
JWT_EXPIRES_IN,
BCRYPT_SALT_ROUNDS,
UUID_NAMESPACE,
SENTRY_DSN,
STRIPE_API_VERSION,
STRIPE_PUBLISHABLE_KEY,
Expand Down
32 changes: 16 additions & 16 deletions src/server/env/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { Algorithm } from "jsonwebtoken";

/**
* @returns a readonly `ENV` object with environment variables used throughout the application.
* @throws an error if required env vars are missing, or if certain env var values are invalid.
Expand All @@ -15,6 +13,7 @@ export const createEnvObject = ({
WEB_CLIENT_URL,
// AWS
AWS_REGION,
DYNAMODB_REGION,
DYNAMODB_TABLE_NAME,
DYNAMODB_ENDPOINT,
PINPOINT_PROJECT_ID,
Expand All @@ -25,6 +24,7 @@ export const createEnvObject = ({
JWT_ISSUER,
JWT_EXPIRES_IN,
BCRYPT_SALT_ROUNDS,
UUID_NAMESPACE,
// SENTRY
SENTRY_DSN,
// STRIPE
Expand Down Expand Up @@ -52,35 +52,33 @@ export const createEnvObject = ({
!JWT_ISSUER ||
!JWT_EXPIRES_IN ||
!BCRYPT_SALT_ROUNDS ||
!SENTRY_DSN ||
!UUID_NAMESPACE ||
!STRIPE_API_VERSION ||
!STRIPE_PUBLISHABLE_KEY ||
!STRIPE_SECRET_KEY ||
!STRIPE_WEBHOOKS_SECRET ||
!GOOGLE_OAUTH_CLIENT_ID ||
!GOOGLE_OAUTH_CLIENT_SECRET
) {
throw new Error("Missing required environment variables.");
throw new Error("Missing required environment variables");
}

// Ensure the provided JWT_ALGORITHM is supported
if (!/^[HRE]S(256|384|512)$/.test(JWT_ALGORITHM)) {
throw new Error("Unsupported JWT_ALGORITHM");
}
if (!/^(development|test|staging|production)$/.test(NODE_ENV))
throw new Error("Unknown NODE_ENV");

const API_BASE_URL = `${PROTOCOL}://${DOMAIN}`;

return {
NODE_ENV,
IS_PROD: /^prod/i.test(NODE_ENV),
IS_DEV: /^dev/i.test(NODE_ENV),
IS_DEPLOYED_ENV: /^(prod|staging)/i.test(NODE_ENV),
IS_DEV: NODE_ENV === "development",
IS_PROD: NODE_ENV === "production",
IS_DEPLOYED_ENV: /^(production|staging)$/.test(NODE_ENV),
CONFIG: {
...(npm_package_version && { PROJECT_VERSION: `v${npm_package_version}` }),
TIMEZONE: new Date().toString().match(/([A-Z]+[+-][0-9]+.*)/)?.[1] ?? "-",
TIMEZONE: new Date().toString().match(/([A-Z]+[+-][0-9]+.*)/)?.[0] ?? "-",
PROTOCOL,
DOMAIN,
PORT,
PORT: Number(PORT),
API_BASE_URL,
API_FULL_URL: `${API_BASE_URL}:${PORT}/api`,
OS_PLATFORM: process.platform,
Expand All @@ -93,18 +91,20 @@ export const createEnvObject = ({
},
AWS: {
REGION: AWS_REGION,
DYNAMODB_REGION: DYNAMODB_REGION ?? AWS_REGION,
DYNAMODB_TABLE_NAME,
...(DYNAMODB_ENDPOINT && { DYNAMODB_ENDPOINT }),
DYNAMODB_ENDPOINT,
PINPOINT_PROJECT_ID,
SES_EMAIL_ADDRESS,
},
JWT: {
PRIVATE_KEY: JWT_PRIVATE_KEY,
ALGORITHM: JWT_ALGORITHM as Algorithm,
ALGORITHM: JWT_ALGORITHM,
ISSUER: JWT_ISSUER,
EXPIRES_IN: JWT_EXPIRES_IN,
},
BCRYPT_SALT_ROUNDS: parseInt(BCRYPT_SALT_ROUNDS, 10),
BCRYPT_SALT_ROUNDS: Number(BCRYPT_SALT_ROUNDS),
UUID_NAMESPACE,
SENTRY_DSN,
STRIPE: {
API_VERSION: STRIPE_API_VERSION,
Expand Down
55 changes: 33 additions & 22 deletions src/types/globals.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import type { HttpError } from "@/utils/httpErrors.js";
import type { JsonValue } from "type-fest";
import type { CombineUnionOfObjects } from "./helpers.js";

/**
* This type is a {@link CombineUnionOfObjects|combination} of the base Error
* class and the app's custom internal HttpError interface. It's used in error
* handlers to allow for greater flexibility in handling errors.
*/
export type ErrorOrHttpError = CombineUnionOfObjects<Error | HttpError>;

declare global {
namespace NodeJS {
Expand All @@ -8,35 +17,37 @@ declare global {
* (with the exception of NODE_ENV, which should always be defined).
*/
interface ProcessEnv {
NODE_ENV?: "development" | "test" | "ci" | "staging" | "production";
npm_package_version?: string;
NODE_ENV?: "development" | "test" | "staging" | "production" | undefined;
npm_package_version?: string | undefined;
// SERVER
PROTOCOL?: string;
DOMAIN?: string;
PORT?: string;
PROTOCOL?: string | undefined;
DOMAIN?: string | undefined;
PORT?: string | undefined;
// WEB CLIENT
WEB_CLIENT_URL?: string;
WEB_CLIENT_URL?: string | undefined;
// AWS
AWS_REGION?: string;
DYNAMODB_TABLE_NAME?: string;
DYNAMODB_ENDPOINT?: string;
PINPOINT_PROJECT_ID?: string;
SES_EMAIL_ADDRESS?: string;
AWS_REGION?: string | undefined;
DYNAMODB_REGION?: string | undefined;
DYNAMODB_TABLE_NAME?: string | undefined;
DYNAMODB_ENDPOINT?: string | undefined;
PINPOINT_PROJECT_ID?: string | undefined;
SES_EMAIL_ADDRESS?: string | undefined;
// AUTH
JWT_PRIVATE_KEY?: string;
JWT_ALGORITHM?: string;
JWT_ISSUER?: string;
JWT_EXPIRES_IN?: string;
BCRYPT_SALT_ROUNDS?: string;
JWT_PRIVATE_KEY?: string | undefined;
JWT_ALGORITHM?: string | undefined;
JWT_ISSUER?: string | undefined;
JWT_EXPIRES_IN?: string | undefined;
BCRYPT_SALT_ROUNDS?: string | undefined;
UUID_NAMESPACE?: string | undefined;
// SENTRY
SENTRY_DSN?: string;
SENTRY_DSN?: string | undefined;
// STRIPE
STRIPE_WEBHOOKS_SECRET?: string;
STRIPE_PUBLISHABLE_KEY?: string;
STRIPE_SECRET_KEY?: string;
STRIPE_WEBHOOKS_SECRET?: string | undefined;
STRIPE_PUBLISHABLE_KEY?: string | undefined;
STRIPE_SECRET_KEY?: string | undefined;
// GOOGLE
GOOGLE_OAUTH_CLIENT_ID?: string;
GOOGLE_OAUTH_CLIENT_SECRET?: string;
GOOGLE_OAUTH_CLIENT_ID?: string | undefined;
GOOGLE_OAUTH_CLIENT_SECRET?: string | undefined;
}
}

Expand Down

0 comments on commit d2cfd4d

Please sign in to comment.