1import * as Neon from "alchemy/Neon";
2import * as Effect from "effect/Effect";
3import * as Schema from "effect/Schema";
4
5export const resources = Effect.gen(function* () {
6 const project = yield* Neon.Project("Project", { region: "aws-us-east-2" });
7 const branch = yield* Neon.Branch("Backend", {
8 project,
9 migrations: "./migrations",
10 });
11 const uploads = yield* Neon.Bucket("Uploads", {
12 branch,
13 access: "private",
14 // A presigned URL authorizes the PUT, not CORS. No browser cookies are used.
15 cors: [
16 {
17 AllowedOrigins: ["*"],
18 AllowedMethods: ["PUT"],
19 AllowedHeaders: ["content-type"],
20 MaxAgeSeconds: 300,
21 },
22 ],
23 forceDestroy: true,
24 });
25 const auth = yield* Neon.Auth("Auth", {
26 branch,
27 name: "Upload journal",
28 allowLocalhost: true,
29 emailAndPassword: {
30 enabled: true,
31 require_email_verification: false,
32 send_verification_email_on_sign_up: false,
33 },
34 });
35 const appOrigin = yield* Effect.sync(
36 () => process.env.UPLOAD_APP_ORIGIN ?? "*",
37 );
38 const publicAssets = yield* Neon.Bucket("PublicAssets", {
39 branch,
40 access: "public_read",
41 forceDestroy: true,
42 });
43 const settings = yield* Neon.Object("Settings", {
44 bucket: uploads,
45 key: "config/settings.json",
46 value: { theme: "system", pageSize: 25 },
47 schema: Schema.Struct({ theme: Schema.String, pageSize: Schema.Number }),
48 });
49 yield* Neon.Object("Welcome", {
50 bucket: publicAssets,
51 key: "welcome.txt",
52 body: "Public read, authenticated write.",
53 contentType: "text/plain",
54 });
55 return { project, branch, uploads, auth, appOrigin, publicAssets, settings };
56});