1import * as Alchemy from "alchemy";
2import * as Cloudflare from "alchemy/Cloudflare";
3import * as Neon from "alchemy/Neon";
4import * as Prisma from "alchemy/Prisma";
5import * as Effect from "effect/Effect";
6
7/**
8 * A Prisma contract + Neon project + branch. Passing the contract's
9 * output to `Prisma.Migrate` orders the deploy:
10 *
11 * 1. `Prisma.Contract` re-emits the contract and plans a migration
12 * package when the contract drifted from the migration graph.
13 * 2. `Prisma.Migrate` applies pending packages to the branch
14 * (graph-ordered, tracked by the database's contract marker).
15 */
16export const NeonDb = Effect.gen(function* () {
17 const { stage } = yield* Alchemy.Stack;
18
19 const contract = yield* Prisma.Contract("app-contract");
20
21 const project = stage.startsWith("pr-")
22 ? yield* Neon.Project.ref("app-db", { stage: `staging-${stage}` })
23 : yield* Neon.Project("app-db", {
24 region: "aws-us-east-1",
25 });
26
27 const branch = yield* Neon.Branch("app-branch", { project });
28
29 const migrate = yield* Prisma.Migrate("app-migrate", {
30 url: branch.connectionUri,
31 contract,
32 });
33
34 return { project, branch, contract, migrate };
35});
36
37export const Hyperdrive = Effect.gen(function* () {
38 const { branch } = yield* NeonDb;
39 return yield* Cloudflare.Hyperdrive.Connection("app-hyperdrive", {
40 origin: branch.origin,
41 caching: { disabled: true },
42 });
43});