1/** The application's HTTP routes: our API and Git, with shared authentication. */
2import * as Http from "alchemy/Http";
3
4import * as Cloudflare from "alchemy/Cloudflare";
5import * as Git from "alchemy/Git";
6import * as Layer from "effect/Layer";
7import { AppApi, MeLive } from "./api.ts";
8import * as Effect from "effect/Effect";
9import * as HttpApiBuilder from "effect/http-api/HttpApiBuilder";
10import { ProtocolLive } from "./protocol.ts";
11import { RefsLive, PullsLive } from "./ref-writes.ts";
12import { GitHubLive } from "./github.ts";
13import { Authentication } from "./middleware.ts";
14
15/** Packs, clone bundles, and spilled pushes. */
16export const GitObjects = Cloudflare.R2.Bucket("GitObjects", {
17 // `bun test` sets NODE_ENV=test: the integration test tears the stack
18 // down with repositories still in the bucket.
19 forceDestroy: process.env.NODE_ENV === "test",
20});
21
22const PublicRoutes = HttpApiBuilder.layer(AppApi).pipe(
23 Layer.provide(
24 Layer.mergeAll(
25 MeLive,
26 ProtocolLive,
27 RefsLive,
28 PullsLive,
29 GitHubLive,
30 HttpApiBuilder.group(AppApi, "repos", (h) =>
31 Effect.map(Git.Handlers, (defaults) => h.handleAll(defaults.repos)),
32 ),
33 HttpApiBuilder.group(AppApi, "objects", (h) =>
34 Effect.map(Git.Handlers, (defaults) => h.handleAll(defaults.objects)),
35 ),
36 ),
37 ),
38 Layer.provide(Authentication.layer),
39);
40
41export const HttpLive = Layer.mergeAll(PublicRoutes, Git.InternalApiLive).pipe(
42 Layer.provide(Git.ApiHandlersLive),
43 Layer.provide(Git.ReposDurableObject),
44 Layer.provide(Git.RegistryDurableObject), // owner/name → repo
45 Layer.provide(Git.HasherInline), // push verification in this Worker
46 Layer.provide(Git.BlobStoreR2(GitObjects)), // packs, bundles, large pushes
47 Layer.provide(Http.Platform),
48);