diff --git a/.github/workflows/ci-daily.yml b/.github/workflows/ci-daily.yml index 2de02397..6400228d 100644 --- a/.github/workflows/ci-daily.yml +++ b/.github/workflows/ci-daily.yml @@ -30,9 +30,6 @@ jobs: - run: moon ci --color --base $HHH_EMPTY_GIT_TREE env: CHROMATIC_PROJECT_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }} - # <.env.test> - EXPO_PUBLIC_REPLICACHE_LICENSE_KEY: HHH_TEST_LICENSE_KEY - # # Magic "empty" tree https://jiby.tech/post/git-diff-empty-repo/, so # that all files are seen as "affected" by moon ci, and thus all CI # tests are run. diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 54b80123..f7b5b3d6 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -97,9 +97,6 @@ jobs: moon-ci: runs-on: ubuntu-latest env: - # <.env.test> - EXPO_PUBLIC_REPLICACHE_LICENSE_KEY: HHH_TEST_LICENSE_KEY - # VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_STATIC }} strategy: diff --git a/projects/app/.env.test b/projects/app/.env.test deleted file mode 100644 index 46774f47..00000000 --- a/projects/app/.env.test +++ /dev/null @@ -1,2 +0,0 @@ -# Keep in sync with Github workflows (search `<.env.test>`) -EXPO_PUBLIC_REPLICACHE_LICENSE_KEY="HHH_TEST_LICENSE_KEY" diff --git a/projects/app/drizzle.config.ts b/projects/app/drizzle.config.ts index 6fc8a14d..c03b175c 100644 --- a/projects/app/drizzle.config.ts +++ b/projects/app/drizzle.config.ts @@ -4,8 +4,4 @@ export default defineConfig({ schema: `./src/server/schema.ts`, out: `./drizzle`, dialect: `postgresql`, - dbCredentials: { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - url: process.env.NEON_DATABASE_URL!, - }, }); diff --git a/projects/app/moon.yml b/projects/app/moon.yml index c411e058..11b95da0 100644 --- a/projects/app/moon.yml +++ b/projects/app/moon.yml @@ -228,7 +228,6 @@ tasks: options: envFile: - .env.local - - .env.test testWatch: command: node --test --watch --import tsx "src/**/*.test.ts" @@ -236,7 +235,6 @@ tasks: options: envFile: - .env.local - - .env.test typecheck: deps: diff --git a/projects/app/src/client/ui/ReplicacheContext.tsx b/projects/app/src/client/ui/ReplicacheContext.tsx index c4bc44e7..97c38116 100644 --- a/projects/app/src/client/ui/ReplicacheContext.tsx +++ b/projects/app/src/client/ui/ReplicacheContext.tsx @@ -1,8 +1,8 @@ import { trpc } from "@/client/trpc"; import { SrsType } from "@/data/model"; import { v4 } from "@/data/rizzleSchema"; -import { replicacheLicenseKey } from "@/env"; import { AppRouter } from "@/server/routers/_app"; +import { failFastIfMissingEnvVars } from "@/util/env"; import { nextReview, UpcomingReview } from "@/util/fsrs"; import { cookieSchema, r, RizzleReplicache } from "@/util/rizzle"; import { invariant } from "@haohaohow/lib/invariant"; @@ -17,13 +17,22 @@ import { useRef, useState, } from "react"; -import { HTTPRequestInfo, PullResponseV1, ReadTransaction } from "replicache"; +import { + HTTPRequestInfo, + PullResponseV1, + ReadTransaction, + TEST_LICENSE_KEY, +} from "replicache"; import { useAuth, UseAuth2Data } from "./auth"; import { kvStore } from "./replicacheOptions"; import { useRenderGuard } from "./util"; export type Rizzle = RizzleReplicache; +if (failFastIfMissingEnvVars) { + invariant(process.env.EXPO_PUBLIC_REPLICACHE_LICENSE_KEY != null); +} + const ReplicacheContext = createContext(null); function ReplicacheProviderWithDeps({ @@ -41,7 +50,8 @@ function ReplicacheProviderWithDeps({ return r.replicache( { name: replicacheDbName, - licenseKey: replicacheLicenseKey, + licenseKey: + process.env.EXPO_PUBLIC_REPLICACHE_LICENSE_KEY ?? TEST_LICENSE_KEY, kvStore, // No need for a custom logSink here, just using normal console.* // functions are fine because `Sentry.captureConsoleIntegration` diff --git a/projects/app/src/client/ui/auth.ts b/projects/app/src/client/ui/auth.ts index e0239423..09e0e20e 100644 --- a/projects/app/src/client/ui/auth.ts +++ b/projects/app/src/client/ui/auth.ts @@ -57,7 +57,7 @@ type AuthApi = { signOut: () => void; }; -// TODO: how to handle beind anonymous then logging in but there's an existing +// TODO: how to handle being anonymous then logging in but there's an existing // user. It's more like "switch user" than it is anything else. Maybe even in // the anonymous case you should have to give your name? Only after you actually // save some useful state. diff --git a/projects/app/src/client/ui/replicacheOptions.web.ts b/projects/app/src/client/ui/replicacheOptions.web.ts index bd3984de..ffbd5532 100644 --- a/projects/app/src/client/ui/replicacheOptions.web.ts +++ b/projects/app/src/client/ui/replicacheOptions.web.ts @@ -1,6 +1,6 @@ import { ReplicacheOptions } from "replicache"; -// Intentionally DO NOT allow Expo top inline the environment variable, +// Intentionally DO NOT allow Expo to inline the environment variable, // otherwise it will leak into the browser bundle otherwise the browser code // will also think it's in static render mode and use the // ExperimentalMemKVStore. diff --git a/projects/app/src/env.ts b/projects/app/src/env.ts deleted file mode 100644 index 5856fe30..00000000 --- a/projects/app/src/env.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { TEST_LICENSE_KEY } from "replicache"; -import z from "zod"; - -const nonEmptyString = z.string().min(1); - -export const replicacheLicenseKey = nonEmptyString - // The special value `HHH_TEST_LICENSE_KEY` swaps to the test key from replicache. - .transform((x) => (x === `HHH_TEST_LICENSE_KEY` ? TEST_LICENSE_KEY : x)) - .parse(process.env.EXPO_PUBLIC_REPLICACHE_LICENSE_KEY); diff --git a/projects/app/src/server/lib/inngest.ts b/projects/app/src/server/lib/inngest.ts index cee83511..8d4fc059 100644 --- a/projects/app/src/server/lib/inngest.ts +++ b/projects/app/src/server/lib/inngest.ts @@ -1,9 +1,16 @@ +import { failFastIfMissingEnvVars } from "@/util/env"; import { invariant } from "@haohaohow/lib/invariant"; import { sentryMiddleware } from "@inngest/middleware-sentry"; import { Inngest } from "inngest"; import * as postmark from "postmark"; import { z } from "zod"; +const { POSTMARK_SERVER_TOKEN } = process.env; + +if (failFastIfMissingEnvVars) { + invariant(POSTMARK_SERVER_TOKEN != null, `POSTMARK_SERVER_TOKEN is required`); +} + // Create a client to send and receive events export const inngest = new Inngest({ id: `my-app`, @@ -69,12 +76,8 @@ const helloWorldEmail = inngest.createFunction( { id: `hello-world-email` }, { event: `test/hello.world.email` }, async ({ step }) => { - invariant( - process.env.POSTMARK_SERVER_TOKEN != null, - `POSTMARK_SERVER_TOKEN is required`, - ); - - const client = new postmark.ServerClient(process.env.POSTMARK_SERVER_TOKEN); + invariant(POSTMARK_SERVER_TOKEN != null); + const client = new postmark.ServerClient(POSTMARK_SERVER_TOKEN); const response = await step.run(`sendEmail`, () => client.sendEmail({ diff --git a/projects/app/src/server/schemaUtil.ts b/projects/app/src/server/schemaUtil.ts index 9378e768..41ea8f93 100644 --- a/projects/app/src/server/schemaUtil.ts +++ b/projects/app/src/server/schemaUtil.ts @@ -1,4 +1,5 @@ import * as r from "@/data/rizzleSchema"; +import { isRunningTests } from "@/util/env"; import { RizzleType, RizzleTypeDef } from "@/util/rizzle"; import { invariant } from "@haohaohow/lib/invariant"; import { ColumnBaseConfig, Table } from "drizzle-orm"; @@ -37,7 +38,7 @@ function unstable__columnName(column: PgCustomColumn): string { * Adds the table and column name to Zod parsing errors to help debugging. */ function drizzleColumnTypeEnhancedErrors(column: PgCustomColumn) { - if (`NODE_TEST_CONTEXT` in process.env || __DEV__) { + if (isRunningTests || __DEV__) { // *always* run this code path so that it fails loudly in tests/dev, rather // than only in the case of a zod parsing. unstable__columnName(column); diff --git a/projects/app/src/typings/node.d.ts b/projects/app/src/typings/node.d.ts index 0aa8fa12..a905d6ef 100644 --- a/projects/app/src/typings/node.d.ts +++ b/projects/app/src/typings/node.d.ts @@ -14,7 +14,6 @@ declare global { EXPO_PUBLIC_REPLICACHE_LICENSE_KEY?: string; EXPO_PUBLIC_SENTRY_DSN?: string; EXPO_PUBLIC_USE_STATIC?: string | boolean; // boolean during static render, string on web - NEON_DATABASE_URL?: string; NODE_ENV?: string; POSTMARK_SERVER_TOKEN?: string; } diff --git a/projects/app/src/util/env.ts b/projects/app/src/util/env.ts new file mode 100644 index 00000000..3c4aa344 --- /dev/null +++ b/projects/app/src/util/env.ts @@ -0,0 +1,9 @@ +// true when running under the Node.js test runner. +export const isRunningTests = `NODE_TEST_CONTEXT` in process.env; + +// true when running CI (e.g. `moon ci`). This can be different from running +// tests (e.g. when `eas build` runs). +export const isRunningCi = `CI` in process.env; + +export const failFastIfMissingEnvVars = + !isRunningTests && !isRunningCi && !__DEV__;