1import {
2 type SourceControlAppAccess,
3 type SourceControlAppAccessInput,
4 SourceControlSignInError,
5 type SourceControlSignInInput,
6 type SourceControlSignInPrompt,
7 type SourceControlSignInResult,
8 type SourceControlStarredInput,
9} from "@t3tools/contracts";
10import * as Context from "effect/Context";
11import * as Effect from "effect/Effect";
12import * as Layer from "effect/Layer";
13
14import * as SourceControlBuiltInDrivers from "./builtInDrivers.ts";
15
16/** Signs the server in to a forge through the forge's own app, and reads what its account did. */
17export class SourceControlSignIn extends Context.Service<
18 SourceControlSignIn,
19 {
20 readonly start: (
21 input: SourceControlSignInInput,
22 ) => Effect.Effect<SourceControlSignInPrompt, SourceControlSignInError>;
23 readonly wait: (
24 input: SourceControlSignInInput,
25 ) => Effect.Effect<SourceControlSignInResult, SourceControlSignInError>;
26 readonly cancel: (
27 input: SourceControlSignInInput,
28 ) => Effect.Effect<void, SourceControlSignInError>;
29 readonly access: (input: SourceControlAppAccessInput) => Effect.Effect<SourceControlAppAccess>;
30 readonly starred: (input: SourceControlStarredInput) => Effect.Effect<boolean>;
31 readonly star: (input: SourceControlStarredInput) => Effect.Effect<boolean>;
32 }
33>()("t3/sourceControl/SourceControlSignIn") {}
34
35const make = Effect.gen(function* () {
36 const drivers = yield* SourceControlBuiltInDrivers.SourceControlDrivers;
37
38 const signInFor = (input: SourceControlSignInInput) => {
39 const signIn = drivers.find(({ driver }) => driver.kind === input.provider)?.instance.signIn;
40 return signIn === undefined
41 ? Effect.fail(
42 new SourceControlSignInError({
43 provider: input.provider,
44 host: input.host,
45 reason: "unsupported",
46 detail: `This server cannot sign in to ${input.provider}. Use a token or the host's CLI.`,
47 }),
48 )
49 : Effect.succeed(signIn);
50 };
51
52 return SourceControlSignIn.of({
53 start: Effect.fn("SourceControlSignIn.start")(function* (input) {
54 return yield* (yield* signInFor(input)).start(input.host);
55 }),
56 wait: Effect.fn("SourceControlSignIn.wait")(function* (input) {
57 return yield* (yield* signInFor(input)).wait(input.host);
58 }),
59 cancel: Effect.fn("SourceControlSignIn.cancel")(function* (input) {
60 return yield* (yield* signInFor(input)).cancel(input.host);
61 }),
62 access: Effect.fn("SourceControlSignIn.access")(function* (input) {
63 const signIn = drivers.find(({ driver }) => driver.kind === input.provider)?.instance.signIn;
64 return {
65 status:
66 signIn === undefined ? "signed-out" : yield* signIn.access(input.host, input.repository),
67 } satisfies SourceControlAppAccess;
68 }),
69 starred: Effect.fn("SourceControlSignIn.starred")(function* (input) {
70 const isStarred = drivers.find(({ driver }) => driver.kind === input.provider)?.instance
71 .isRepositoryStarred;
72 return isStarred === undefined ? false : yield* isStarred(input.host, input.repository);
73 }),
74 star: Effect.fn("SourceControlSignIn.star")(function* (input) {
75 const star = drivers.find(({ driver }) => driver.kind === input.provider)?.instance
76 .starRepository;
77 return star === undefined ? false : yield* star(input.host, input.repository);
78 }),
79 });
80});
81
82export const layer = Layer.effect(SourceControlSignIn, make);