Eric Bower
·
27 Nov 22
stht.ts
1import type { FetchRepoProps, Resp } from "./types.ts";
2
3interface SrhtRepo {
4 id: string;
5 name: string;
6 created: string;
7 updated: string;
8 readme: string | null;
9 description: string;
10 HEAD: { name: string };
11}
12
13interface SrhtRepoResp {
14 data: {
15 user: {
16 repository: SrhtRepo;
17 };
18 };
19}
20
21async function fetchReadme(
22 props: FetchRepoProps,
23 branch: string,
24 fpath = "README.md",
25): Promise<Resp<string>> {
26 const url =
27 `https://git.sr.ht/~${props.username}/${props.repo}/blob/${branch}/${fpath}`;
28 console.log(`Fetching ${url}`);
29 const resp = await fetch(url);
30 const readme = await resp.text();
31 if (!resp.ok) {
32 return {
33 ok: false,
34 data: {
35 status: resp.status,
36 error: new Error(`failed to fetch srht readme: ${readme}`),
37 },
38 };
39 }
40
41 return { ok: true, data: readme };
42}
43
44async function recurseReadme(
45 props: FetchRepoProps,
46 branch: string,
47 fnames: string[],
48) {
49 for (let i = 0; i < fnames.length; i += 1) {
50 const readme = await fetchReadme(props, branch, fnames[i]);
51
52 if (readme.ok) {
53 return readme.data;
54 } else {
55 console.log(`${readme.data.status}: ${readme.data.error.message}`);
56 }
57 }
58
59 return "";
60}
61
62interface SrhtData {
63 repo: SrhtRepo;
64 branch: string;
65 readme: string;
66}
67
68export async function fetchSrhtData(
69 props: FetchRepoProps,
70): Promise<Resp<SrhtData>> {
71 const query = `\
72 query {\
73 user(username: "${props.username}") {\
74 repository(name: "${props.repo}") {\
75 id,\
76 name,\
77 created,\
78 updated,\
79 readme,\
80 description,\
81 HEAD { name }\
82 }\
83 }\
84 }`;
85 const body = { query };
86
87 const payload = {
88 method: "POST",
89 headers: {
90 Authorization: `Bearer ${props.token}`,
91 ["Content-Type"]: "application/json",
92 },
93 body: JSON.stringify(body),
94 };
95 const url = "https://git.sr.ht/query";
96 console.log(`Fetching ${url} [${props.username}/${props.repo}]`);
97 const resp = await fetch(url, payload);
98
99 if (!resp.ok) {
100 return {
101 ok: false,
102 data: { status: resp.status, error: new Error("request failed") },
103 };
104 }
105
106 const data: SrhtRepoResp = await resp.json();
107 const repo = data.data.user.repository;
108 const name = repo.HEAD.name;
109 const ref = name.split("/");
110 const branch = ref[ref.length - 1];
111 let readmeData = "";
112 if (repo.readme) {
113 readmeData = repo.readme;
114 } else {
115 // supported readme: https://git.sr.ht/~sircmpwn/scm.sr.ht/tree/83185bf27e1e67ab2ce88851dc7a3f7766075a60/item/scmsrht/formatting.py#L25
116 const fnames = ["README.md", "README.markdown", "README"];
117 readmeData = await recurseReadme(props, branch, fnames);
118 }
119
120 return {
121 ok: true,
122 data: {
123 repo,
124 branch,
125 readme: readmeData,
126 },
127 };
128}