103 lines
3.2 KiB
TypeScript
103 lines
3.2 KiB
TypeScript
import { isRecord } from '@/lib/guards'
|
|
import type { RemoteFile } from '@/lib/types'
|
|
import { decodeBase64Content, encodePath, getRepoApiPath, isHttpError, requestGitJson } from './http'
|
|
import { isLfsFile, parseLfsPointer } from './lfs'
|
|
import type { GitRemoteConfig } from './types'
|
|
|
|
interface GitContentEntry {
|
|
content?: string
|
|
name: string
|
|
path?: string
|
|
sha?: string
|
|
size?: number
|
|
type?: string
|
|
}
|
|
|
|
function isGitContentEntry(value: unknown): value is GitContentEntry {
|
|
return isRecord(value)
|
|
&& typeof value.name === 'string'
|
|
&& (value.path === undefined || typeof value.path === 'string')
|
|
&& (value.sha === undefined || typeof value.sha === 'string')
|
|
&& (value.size === undefined || typeof value.size === 'number')
|
|
&& (value.content === undefined || typeof value.content === 'string')
|
|
&& (value.type === undefined || typeof value.type === 'string')
|
|
}
|
|
|
|
function getContentEntrySize(entry: GitContentEntry) {
|
|
return entry.size ?? 0
|
|
}
|
|
|
|
async function getRemoteContent(remote: GitRemoteConfig, path: string, branch: string) {
|
|
const query = new URLSearchParams({ ref: branch })
|
|
return requestGitJson(remote, `${getRepoApiPath(remote)}/contents/${encodePath(path)}?${query.toString()}`)
|
|
}
|
|
|
|
export function getRequiredContentEntrySha(entry: GitContentEntry, path: string) {
|
|
if (!entry.sha) {
|
|
throw new Error(`SHA Git manquant pour ${path}`)
|
|
}
|
|
|
|
return entry.sha
|
|
}
|
|
|
|
export async function getRemoteFileEntry(remote: GitRemoteConfig, path: string, branch: string): Promise<GitContentEntry | null> {
|
|
try {
|
|
const data = await getRemoteContent(remote, path, branch)
|
|
return isGitContentEntry(data) ? data : null
|
|
} catch (err) {
|
|
if (isHttpError(err) && err.status === 404) return null
|
|
throw err
|
|
}
|
|
}
|
|
|
|
export async function readRemoteFolder(
|
|
remote: GitRemoteConfig,
|
|
branch: string,
|
|
folderPath: string,
|
|
): Promise<{ exists: boolean; files: RemoteFile[] }> {
|
|
try {
|
|
const data = await getRemoteContent(remote, folderPath, branch)
|
|
|
|
if (!Array.isArray(data)) {
|
|
throw new Error(`Le chemin distant ${folderPath} existe mais ce n'est pas un dossier`)
|
|
}
|
|
|
|
const files: RemoteFile[] = await Promise.all(
|
|
data.map(async (entry: unknown): Promise<RemoteFile> => {
|
|
if (!isGitContentEntry(entry)) {
|
|
throw new Error(`Reponse Git invalide pour ${folderPath}`)
|
|
}
|
|
|
|
const size = getContentEntrySize(entry)
|
|
|
|
if (!isLfsFile(entry.name) || size > 1024) {
|
|
return { name: entry.name, size }
|
|
}
|
|
|
|
try {
|
|
const fileData = await getRemoteFileEntry(remote, `${folderPath}/${entry.name}`, branch)
|
|
|
|
if (fileData?.content) {
|
|
const content = decodeBase64Content(fileData.content)
|
|
const pointer = parseLfsPointer(content)
|
|
if (pointer) {
|
|
return { name: entry.name, size: pointer.size }
|
|
}
|
|
}
|
|
} catch (err) {
|
|
if (!isHttpError(err) || err.status !== 404) throw err
|
|
}
|
|
|
|
return { name: entry.name, size }
|
|
}),
|
|
)
|
|
|
|
return { exists: true, files }
|
|
} catch (err: unknown) {
|
|
if (isHttpError(err) && err.status === 404) {
|
|
return { exists: false, files: [] }
|
|
}
|
|
throw err
|
|
}
|
|
}
|