1/**
2 * The `objects` group: commit, log, tree, blob, diff, and compare reads,
3 * plus the two raw streaming reads (DESIGN.md §5): a blob's bytes as an
4 * octet-stream, and a file at a path under a ref. The raw routes declare
5 * no success schema and answer with the response they build.
6 */
7import * as HttpApiEndpoint from "effect/http-api/HttpApiEndpoint";
8import * as Schema from "effect/Schema";
9import * as HttpApiGroup from "effect/http-api/HttpApiGroup";
10import {
11 CommitDiff,
12 CommitInfo,
13 Comparison,
14 NoMergeBase,
15 ObjectNotFound,
16 ObjectTooLarge,
17 Oid,
18 Paginated,
19 RefNotFound,
20 RepoNotFound,
21 RepoOidPath,
22 RepoPath,
23 TreeEntry,
24 WrongObjectType,
25} from "./Schema.ts";
26
27/** Reads one commit. */
28export const GetCommit = HttpApiEndpoint.get(
29 "commit",
30 "/repos/:owner/:repo/commits/:oid",
31 {
32 params: RepoOidPath,
33 success: CommitInfo,
34 error: [RepoNotFound, ObjectNotFound, WrongObjectType],
35 },
36);
37
38/** Pages the commit history from a ref or oid. */
39export const GetLog = HttpApiEndpoint.get("log", "/repos/:owner/:repo/log", {
40 params: RepoPath,
41 query: Schema.Struct({
42 /** Refname or oid to start from. @default HEAD */
43 ref: Schema.optional(Schema.String),
44 cursor: Schema.optional(Schema.String),
45 limit: Schema.optional(
46 Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 100 })),
47 ),
48 }),
49 success: Paginated(CommitInfo),
50 error: [RepoNotFound, RefNotFound],
51});
52
53/** Reads one tree's entries. */
54export const GetTree = HttpApiEndpoint.get(
55 "tree",
56 "/repos/:owner/:repo/trees/:oid",
57 {
58 params: RepoOidPath,
59 success: Schema.Struct({
60 oid: Oid,
61 entries: Schema.Array(TreeEntry),
62 }),
63 error: [RepoNotFound, ObjectNotFound, WrongObjectType],
64 },
65);
66
67/** Reads a small blob as base64 JSON (≤ 1 MiB; 422 otherwise — use /raw). */
68export const GetBlob = HttpApiEndpoint.get(
69 "blob",
70 "/repos/:owner/:repo/blobs/:oid",
71 {
72 params: RepoOidPath,
73 success: Schema.Struct({
74 oid: Oid,
75 /** Uncompressed size in bytes. */
76 size: Schema.Number,
77 encoding: Schema.Literals(["base64"]),
78 /** Base64 content — blobs ≤ 1 MiB only (422 otherwise; use /raw). */
79 content: Schema.String,
80 }),
81 error: [RepoNotFound, ObjectNotFound, WrongObjectType, ObjectTooLarge],
82 },
83);
84
85/**
86 * The changed-file list of a commit vs its FIRST parent (empty tree for a
87 * root commit). Merge commits are diffed against parent[0] only — the
88 * GitHub default. No rename detection in v1: a rename appears as
89 * `removed` + `added`; clients may pair entries whose old/new oids match
90 * for a cheap exact-rename display.
91 */
92export const GetDiff = HttpApiEndpoint.get(
93 "diff",
94 "/repos/:owner/:repo/commits/:oid/diff",
95 {
96 params: RepoOidPath,
97 success: CommitDiff,
98 error: [RepoNotFound, ObjectNotFound, WrongObjectType],
99 },
100);
101
102/**
103 * Three-dot comparison: merge base, ahead/behind counts, head-side
104 * commits, and the file diff of mergeBase..head. `base`/`head` accept a
105 * refname (short or full) or a 40-hex oid; annotated tags are peeled.
106 */
107export const Compare = HttpApiEndpoint.get(
108 "compare",
109 "/repos/:owner/:repo/compare",
110 {
111 params: RepoPath,
112 query: Schema.Struct({
113 /** Refname or oid of the base side. */
114 base: Schema.String,
115 /** Refname or oid of the head side. */
116 head: Schema.String,
117 }),
118 success: Comparison,
119 error: [
120 RepoNotFound,
121 RefNotFound,
122 ObjectNotFound,
123 WrongObjectType,
124 NoMergeBase,
125 ],
126 },
127);
128
129/**
130 * A blob's bytes as an octet-stream, no size cap (the per-object 64 MiB
131 * ingest cap is the outer bound). Streams the response it builds.
132 */
133export const GetBlobRaw = HttpApiEndpoint.get(
134 "blobRaw",
135 "/repos/:owner/:repo/blobs/:oid/raw",
136 {},
137);
138
139/**
140 * A file at `?path=` under `?ref=` (refname or oid; the default branch
141 * when absent), walked tree by tree, as an octet-stream.
142 */
143export const GetFile = HttpApiEndpoint.get(
144 "file",
145 "/repos/:owner/:repo/file",
146 {},
147);
148
149/** The `objects` group, mounted at `/api/v1`. */
150export class Objects extends HttpApiGroup.make("objects")
151 .add(
152 GetCommit,
153 GetLog,
154 GetTree,
155 GetBlob,
156 GetDiff,
157 Compare,
158 GetBlobRaw,
159 GetFile,
160 )
161 .prefix("/api/v1") {}