1import {
2 type ReviewDiffPreviewInput,
3 VcsUnsupportedOperationError,
4 WS_METHODS,
5} from "@t3tools/contracts";
6import * as Effect from "effect/Effect";
7import * as Semaphore from "effect/Semaphore";
8import { request } from "../rpc/client.ts";
9import { Atom } from "effect/reactivity";
10
11import {
12 createAtomCommandScheduler,
13 createEnvironmentRpcCommand,
14 createEnvironmentQueryAtomFamily,
15 createEnvironmentRpcQueryAtomFamily,
16} from "./runtime.ts";
17import type { EnvironmentRegistry } from "../connection/registry.ts";
18
19export function createReviewEnvironmentAtoms<R, E>(
20 runtime: Atom.AtomRuntime<EnvironmentRegistry | R, E>,
21) {
22 const patchReads = Semaphore.makeUnsafe(4);
23 const diffFileScheduler = createAtomCommandScheduler();
24 return {
25 diffPreview: createEnvironmentRpcQueryAtomFamily(runtime, {
26 label: "environment-data:review:diff-preview",
27 tag: WS_METHODS.reviewGetDiffPreview,
28 staleTimeMs: 5_000,
29 }),
30 diffFilePatch: createEnvironmentQueryAtomFamily(runtime, {
31 label: "environment-data:review:diff-file-patch",
32 staleTimeMs: 5 * 60_000,
33 execute: (input: {
34 request: ReviewDiffPreviewInput & { file: NonNullable<ReviewDiffPreviewInput["file"]> };
35 cacheKey: string;
36 }) =>
37 request(WS_METHODS.reviewGetDiffPreview, input.request).pipe(
38 patchReads.withPermit,
39 Effect.flatMap((result) => {
40 const source = result.sources.find(
41 (source) => source.kind === input.request.file.sourceKind,
42 );
43 return source
44 ? Effect.succeed(source)
45 : Effect.fail(
46 new VcsUnsupportedOperationError({
47 operation: "review.diffFilePatch",
48 kind: "git",
49 detail: "Diff no longer available. Refresh the comparison.",
50 }),
51 );
52 }),
53 ),
54 }),
55 diffFileContents: createEnvironmentRpcCommand(runtime, {
56 label: "environment-data:review:diff-file-contents",
57 tag: WS_METHODS.reviewGetDiffFileContents,
58 scheduler: diffFileScheduler,
59 concurrency: {
60 mode: "singleFlight",
61 key: ({ environmentId, input }) =>
62 JSON.stringify([
63 environmentId,
64 input.cwd,
65 input.sourceKind,
66 input.baseRef,
67 input.headRef,
68 input.oldPath,
69 input.newPath,
70 input.changeType,
71 ]),
72 },
73 }),
74 };
75}