Skip to content

Commit f0ed5fe

Browse files
committed
add authorization using GITHUB_TOKEN
1 parent 296abb6 commit f0ed5fe

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

app/utils/documents.server.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import path from 'node:path'
55
import * as graymatter from 'gray-matter'
66
import { fetchCached } from '~/utils/cache.server'
77
import { multiSortBy, removeLeadingSlash } from './utils'
8+
import { env } from './env'
89

910
export type Doc = {
1011
filepath: string
@@ -488,8 +489,15 @@ async function fetchApiContentsRemote(
488489
branch: string,
489490
startingPath: string
490491
): Promise<Array<GitHubFileNode> | null> {
492+
const fetchOptions: RequestInit = {
493+
headers: {
494+
'X-GitHub-Api-Version': '2022-11-28',
495+
Authorization: `Bearer ${env.GITHUB_AUTH_TOKEN}`,
496+
},
497+
}
491498
const res = await fetch(
492-
`https://api.github.com/repos/${repo}/contents/${startingPath}?=${branch}`
499+
`https://api.github.com/repos/${repo}/contents/${startingPath}?=${branch}`,
500+
fetchOptions
493501
)
494502

495503
if (!res.ok) {
@@ -525,9 +533,13 @@ async function fetchApiContentsRemote(
525533
}
526534

527535
if (file.type === 'dir' && depth <= API_CONTENTS_MAX_DEPTH) {
528-
const directoryFiles = (await fetch(file._links.self).then((res) =>
529-
res.json()
530-
)) as Array<GitHubFile>
536+
const directoryFilesResponse = await fetch(
537+
file._links.self,
538+
fetchOptions
539+
)
540+
const directoryFiles =
541+
(await directoryFilesResponse.json()) as Array<GitHubFile>
542+
531543
file.children = await buildFileTree(
532544
directoryFiles,
533545
depth + 1,

app/utils/env.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import 'dotenv/config'
2+
import { z } from 'zod'
3+
4+
// Define server-only schema
5+
const serverEnvSchema = z.object({
6+
GITHUB_AUTH_TOKEN: z.string().default('USE_A_REAL_KEY_IN_PRODUCTION'),
7+
AIRTABLE_API_KEY: z.string().optional(),
8+
})
9+
10+
// Define client schema
11+
const viteEnvSchema = z.object({
12+
VITE_CLERK_PUBLISHABLE_KEY: z.string().optional(),
13+
})
14+
15+
// Validate and parse environment variables
16+
const parsedServerEnv = import.meta.env.SSR
17+
? serverEnvSchema.parse(process.env)
18+
: {}
19+
const parsedClientEnv = viteEnvSchema.parse(import.meta.env)
20+
21+
type ParsedServerEnv = z.infer<typeof serverEnvSchema>
22+
type ParsedClientEnv = z.infer<typeof viteEnvSchema>
23+
type ParsedEnv = ParsedServerEnv & ParsedClientEnv
24+
25+
// Merge parsed environments, with server env hidden from client
26+
export const env = new Proxy(
27+
import.meta.env.SSR
28+
? { ...parsedClientEnv, ...parsedServerEnv }
29+
: parsedClientEnv,
30+
{
31+
get(target, prop) {
32+
if (prop in parsedServerEnv && typeof window !== 'undefined') {
33+
throw new Error(
34+
`Access to server-only environment variable '${String(
35+
prop
36+
)}' from client code is not allowed.`
37+
)
38+
}
39+
return prop in parsedServerEnv
40+
? parsedServerEnv[prop as keyof typeof parsedServerEnv]
41+
: target[prop as keyof typeof parsedClientEnv]
42+
},
43+
}
44+
) as ParsedEnv

0 commit comments

Comments
 (0)