Skip to content

Commit 87c3648

Browse files
authored
fix: resolve symlinked files (#191)
* fix: resolve symlinked files mcansh/remix-fastify root README is a symlink to the README in packages/remix-fastify and using the raw.github... doesnt follow the redirect Signed-off-by: Logan McAnsh <logan@mcan.sh> * chore: use `getReadme` to allow for any valid readme file name omitting the ref will use the repos default branch Signed-off-by: Logan McAnsh <logan@mcan.sh> * chore: pass octokit around Signed-off-by: Logan McAnsh <logan@mcan.sh> * chore: re-use CacheContext type Signed-off-by: Logan McAnsh <logan@mcan.sh> * chore: use `format: raw` Signed-off-by: Logan McAnsh <logan@mcan.sh> --------- Signed-off-by: Logan McAnsh <logan@mcan.sh>
1 parent 6a5ec1f commit 87c3648

File tree

8 files changed

+59
-32
lines changed

8 files changed

+59
-32
lines changed

app/lib/gh-docs/branches.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { LRUCache } from "lru-cache";
2-
import type { Octokit } from "octokit";
2+
import type { CacheContext } from ".";
33

4-
type CacheContext = { octokit: Octokit };
54
declare global {
65
var branchesCache: LRUCache<string, string[], CacheContext>;
76
}

app/lib/gh-docs/docs.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { getRepoTarballStream } from "./repo-tarball";
66
import { createTarFileProcessor } from "./tarball.server";
77
import { load as $ } from "cheerio";
88
import { env } from "~/env.server";
9+
import type { CacheContext } from ".";
910

1011
interface MenuDocAttributes {
1112
title: string;
@@ -29,7 +30,7 @@ export interface Doc extends Omit<MenuDoc, "hasContent"> {
2930

3031
declare global {
3132
var menuCache: LRUCache<string, MenuDoc[]>;
32-
var docCache: LRUCache<string, Doc>;
33+
var docCache: LRUCache<string, Doc, CacheContext>;
3334
}
3435

3536
let NO_CACHE = env.NO_CACHE;
@@ -81,19 +82,22 @@ function parseAttrs(
8182
* let's have simpler and faster deployments with just one origin server, but
8283
* still distribute the documents across the CDN.
8384
*/
84-
global.docCache ??= new LRUCache<string, Doc>({
85-
// let docCache = new LRUCache<string, Doc | undefined>({
85+
global.docCache ??= new LRUCache<string, Doc, CacheContext>({
8686
max: 300,
8787
ttl: NO_CACHE ? 1 : 1000 * 60 * 5, // 5 minutes
8888
allowStale: !NO_CACHE,
8989
noDeleteOnFetchRejection: true,
9090
fetchMethod: fetchDoc,
9191
});
9292

93-
async function fetchDoc(key: string): Promise<Doc> {
93+
async function fetchDoc(
94+
key: string,
95+
_staleValue: Doc | undefined,
96+
{ context }: LRUCache.FetchOptionsWithContext<string, Doc, CacheContext>,
97+
): Promise<Doc> {
9498
let [repo, ref, slug] = key.split(":");
9599
let filename = `${slug}.md`;
96-
let md = await getRepoContent(repo, ref, filename);
100+
let md = await getRepoContent(repo, ref, filename, context);
97101
if (md === null) {
98102
throw Error(`Could not find ${filename} in ${repo}@${ref}`);
99103
}
@@ -124,9 +128,10 @@ export async function getDoc(
124128
repo: string,
125129
ref: string,
126130
slug: string,
131+
context: CacheContext,
127132
): Promise<Doc | undefined> {
128133
let key = `${repo}:${ref}:${slug}`;
129-
let doc = await docCache.fetch(key);
134+
let doc = await docCache.fetch(key, { context });
130135

131136
return doc || undefined;
132137
}

app/lib/gh-docs/index.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export {
1515

1616
export type { Doc } from "./docs";
1717

18+
export type CacheContext = { octokit: Octokit };
19+
1820
const REPO = env.SOURCE_REPO;
1921
const RELEASE_PACKAGE = env.RELEASE_PACKAGE;
2022

@@ -48,8 +50,8 @@ export function getRepoDocsMenu(ref: string, lang: string) {
4850
return getMenu(REPO, fixupRefName(ref), lang);
4951
}
5052

51-
export function getRepoDoc(ref: string, slug: string) {
52-
return getDoc(REPO, fixupRefName(ref), slug);
53+
export function getRepoDoc(ref: string, slug: string, context: CacheContext) {
54+
return getDoc(REPO, fixupRefName(ref), slug, context);
5355
}
5456

5557
function fixupRefName(ref: string) {

app/lib/gh-docs/repo-content.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import path from "path";
33
import invariant from "tiny-invariant";
44
import { env } from "~/env.server";
55

6+
import type { CacheContext } from ".";
7+
68
/**
79
* Fetches the contents of a file in a repository or from your local disk.
810
*
@@ -14,16 +16,22 @@ export async function getRepoContent(
1416
repoPair: string,
1517
ref: string,
1618
filepath: string,
19+
context: CacheContext,
1720
): Promise<string | null> {
1821
if (ref === "local") return getLocalContent(filepath);
1922
let [owner, repo] = repoPair.split("/");
20-
let pathname = `/${owner}/${repo}/${ref}/${filepath}`;
21-
let response = await fetch(
22-
new URL(pathname, "https://raw.githubusercontent.com/").href,
23-
{ headers: { "User-Agent": `docs:${owner}/${repo}` } },
24-
);
25-
if (!response.ok) return null;
26-
return response.text();
23+
let contents = await context.octokit.rest.repos.getContent({
24+
owner,
25+
repo,
26+
ref,
27+
path: filepath,
28+
mediaType: { format: "raw" },
29+
});
30+
31+
// when using `format: raw` the data property is the file contents
32+
let md = contents.data as unknown;
33+
if (md == null || typeof md !== "string") return null;
34+
return md;
2735
}
2836

2937
/**

app/lib/gh-docs/tags.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ import { LRUCache } from "lru-cache";
22
import parseLinkHeader from "parse-link-header";
33
import semver from "semver";
44
import type { Octokit } from "octokit";
5+
import type { CacheContext as BaseCacheContext } from ".";
56

6-
type CacheContext = { octokit: Octokit; releasePackage: string };
7+
type CacheContext = BaseCacheContext & { releasePackage: string };
78
declare global {
89
var tagsCache: LRUCache<string, string[], CacheContext>;
910
}

app/lib/resources.server.ts

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import yaml from "yaml";
22
import { LRUCache } from "lru-cache";
33
import { env } from "~/env.server";
4-
import { getRepoContent } from "./gh-docs/repo-content";
54
import { processMarkdown } from "./md.server";
6-
import type { Octokit } from "octokit";
75
import resourcesYamlFileContents from "../../data/resources.yaml?raw";
86
import { slugify } from "~/ui/primitives/utils";
7+
import type { CacheContext } from "./gh-docs";
98

109
// TODO: parse this with zod
1110
let _resources: ResourceYamlData[] = yaml.parse(resourcesYamlFileContents);
@@ -36,7 +35,6 @@ type ResourceYamlKeys =
3635
| "featured";
3736
type ResourceYamlData = Pick<Resource, ResourceYamlKeys>;
3837
type ResourceGitHubData = Omit<Resource, ResourceYamlKeys>;
39-
type CacheContext = { octokit: Octokit };
4038

4139
/**
4240
* Gets all of the resources, fetching and merging GitHub data for each one
@@ -73,7 +71,7 @@ export async function getResource(
7371

7472
let [gitHubData, readmeHtml] = await Promise.all([
7573
getResourceGitHubData(resource.repoUrl, { octokit }),
76-
getResourceReadme(resource.repoUrl),
74+
getResourceReadme(resource.repoUrl, { octokit }),
7775
]);
7876

7977
if (!gitHubData || !readmeHtml) {
@@ -86,7 +84,7 @@ export async function getResource(
8684
//#region LRUCache and fetchers for GitHub data and READMEs
8785

8886
declare global {
89-
var resourceReadmeCache: LRUCache<string, string>;
87+
var resourceReadmeCache: LRUCache<string, string, CacheContext>;
9088
var resourceGitHubDataCache: LRUCache<
9189
string,
9290
ResourceGitHubData,
@@ -96,26 +94,38 @@ declare global {
9694

9795
let NO_CACHE = env.NO_CACHE;
9896

99-
global.resourceReadmeCache ??= new LRUCache<string, string>({
97+
global.resourceReadmeCache ??= new LRUCache<string, string, CacheContext>({
10098
max: 300,
10199
ttl: NO_CACHE ? 1 : 1000 * 60 * 5, // 5 minutes
102100
allowStale: !NO_CACHE,
103101
noDeleteOnFetchRejection: true,
104102
fetchMethod: fetchReadme,
105103
});
106104

107-
async function fetchReadme(repo: string): Promise<string> {
108-
let md = await getRepoContent(repo, "main", "README.md");
109-
if (md === null) {
110-
throw Error(`Could not find README in ${repo}`);
105+
async function fetchReadme(
106+
key: string,
107+
_staleValue: string | undefined,
108+
{ context }: LRUCache.FetchOptionsWithContext<string, string, CacheContext>,
109+
): Promise<string> {
110+
let [owner, repo] = key.split("/");
111+
let contents = await context.octokit.rest.repos.getReadme({
112+
owner,
113+
repo,
114+
mediaType: { format: "raw" },
115+
});
116+
117+
// when using `format: raw` the data property is the file contents
118+
let md = contents.data as unknown;
119+
if (md == null || typeof md !== "string") {
120+
throw Error(`Could not find README in ${key}`);
111121
}
112122
let { html } = await processMarkdown(md);
113123
return html;
114124
}
115125

116-
async function getResourceReadme(repoUrl: string) {
126+
async function getResourceReadme(repoUrl: string, context: CacheContext) {
117127
let repo = repoUrl.replace("https://github.com/", "");
118-
let doc = await resourceReadmeCache.fetch(repo);
128+
let doc = await resourceReadmeCache.fetch(repo, { context });
119129

120130
return doc || undefined;
121131
}

app/routes/$.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { handleRedirects } from "~/lib/http.server";
22
import type { LoaderFunctionArgs } from "@remix-run/node";
33
import { redirect, json } from "@remix-run/node";
44
import { getRepoDoc } from "~/lib/gh-docs";
5+
import { octokit } from "~/lib/github.server";
56

67
// We use the catch-all route to attempt to find a doc for the given path. If a
78
// doc isn't found, we return a 404 as expected. However we also log those
@@ -55,7 +56,7 @@ export const loader = async ({ request, params }: LoaderFunctionArgs) => {
5556
try {
5657
let ref = "main";
5758
let lang = "en";
58-
let doc = await getRepoDoc(ref, `docs/${params["*"]}`);
59+
let doc = await getRepoDoc(ref, `docs/${params["*"]}`, { octokit });
5960
if (!doc) throw null;
6061
// FIXME: This results in two fetches, as the loader for the docs page will
6162
// repeat the request cycle. This isn't a problem if the doc is in the LRU

app/routes/docs.$lang.$ref.$.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import cx from "clsx";
2424
import { useDelegatedReactRouterLinks } from "~/ui/delegate-links";
2525
import type { loader as docsLayoutLoader } from "~/routes/docs.$lang.$ref";
2626
import type { loader as rootLoader } from "~/root";
27+
import { octokit } from "~/lib/github.server";
2728

2829
export async function loader({ params, request }: LoaderFunctionArgs) {
2930
let url = new URL(request.url);
@@ -33,7 +34,7 @@ export async function loader({ params, request }: LoaderFunctionArgs) {
3334
let slug = params["*"]?.endsWith("/changelog")
3435
? "CHANGELOG"
3536
: `docs/${params["*"] || "index"}`;
36-
let doc = await getRepoDoc(params.ref, slug);
37+
let doc = await getRepoDoc(params.ref, slug, { octokit });
3738
if (!doc) throw null;
3839
return json(
3940
{ doc, pageUrl },

0 commit comments

Comments
 (0)