license import { Auth , Repo } from "./auth" ; export interface File { path : string ; sha : string ; } /**
 * Token that is thrown when we cannot cat a file becasue it does not exist.
 */ export class FileNotFound { message : string = "This file does not exist." ; } export async function getRepo ( accessToken , username , repoName ) { const response = await fetch ( `https://api.github.com/repos/${ username }/${ repoName }?cache_bust=${ new Date ( ) . getTime ( ) }` , { headers : { Accept : "application/json" , Authorization : `token ${ accessToken }` , } , } ) ; if ( response . status === 404 ) { throw new FileNotFound ( ) ; } else if ( response . status >= 400 ) { throw new Error ( "Could not get repo" ) ; } return response . json ( ) ; } export async function createRepo ( accessToken , username , repoName ) { const response = await fetch ( `https://api.github.com/user/repos?cache_bust=${ new Date ( ) . getTime ( ) }` , { body : JSON . stringify ( { auto_init : true , description : `Sheet music by ${ username }` , has_issues : false , has_pages : true , has_projects : false , has_wiki : false , homepage : `https://${ username }.github.io/sheet-music` , name : repoName , } ) , headers : { Accept : "application/json" , Authorization : `token ${ accessToken }` , "Content-Type" : "application/json" , } , method : "POST" , } ) ; if ( response . status >= 400 ) { throw new Error ( "Could not create repo" ) ; } return response . json ( ) ; } export async function getOrCreateRepo ( auth ) { const repoParts = auth . repo . split ( "/" ) ; if ( repoParts . length !== 2 ) { throw new Error ( "Could not get repo details." ) ; } let repo ; try { repo = await getRepo ( auth . accessToken , repoParts [ 0 ] , repoParts [ 1 ] ) ; } catch ( err ) { if ( err instanceof FileNotFound ) { if ( repoParts [ 0 ] !== auth . username ) { throw new Error ( "Invalid repo." ) ; } repo = await createRepo ( auth . accessToken , repoParts [ 0 ] , repoParts [ 1 ] ) ; } else { throw err ; } } return repo ; } export async function getDefaultBranch ( accessToken , repo ) { const headers = accessToken ? { Authorization : `token ${ accessToken }` , } : { } ; const response = await fetch ( `https://api.github.com/repos/${ repo }` , { headers , } ) ; return ( await response . json ( ) ) . default_branch ?? "master" ; } export async function ls ( accessToken , repo ) { const headers = { Authorization : `token ${ accessToken }` , } ; const response = await fetch ( `https://api.github.com/repos/${ repo }/contents?ref=${ await getDefaultBranch ( accessToken , repo ) }&cache_bust=${ new Date ( ) . getTime ( ) }` , { headers , } ) ; return ( await response . json ( ) ) . map ( ( file ) => ( { path : file . path , sha : file . sha , } ) ) ; } /**
 * Token that is thrown when we cannot save a file to GitHub because it already
 * exists, or was modified between when we got the SHA and when we made the save request.
 */ export class Conflict { message : string = "Cannot save file because it conflicts with another file." ; } function b64DecodeUnicode ( str ) { return decodeURIComponent ( atob ( str ) . split ( "" ) . map ( ( c ) => "%" + ( "00" + c . charCodeAt ( 0 ) . toString ( 16 ) ) . slice ( - 2 ) ) . join ( "" ) ) ; } export async function cat ( accessToken , repo , filename ) { const headers = { Authorization : `token ${ accessToken }` , } ; const response = await fetch ( `https://api.github.com/repos/${ repo }/contents/${ filename }?ref=${ await getDefaultBranch ( accessToken , repo ) }` + `&cache_bust=${ new Date ( ) . getTime ( ) }` , { headers , } ) ; if ( response . status === 404 ) { throw new FileNotFound ( ) ; } const obj = await response . json ( ) ; return { content : b64DecodeUnicode ( obj . content ) , sha : obj . sha , } ; } export async function write ( accessToken , repo , filename , base64 , sha ? ) { const response = await fetch ( `https://api.github.com/repos/${ repo }/contents/${ filename }` , { body : JSON . stringify ( { branch : await getDefaultBranch ( accessToken , repo ) , content : base64 , message : `Saved via ${ process . env . HOMEPAGE || "Hacklily" }` , sha : sha ? sha : undefined , } ) , headers : { Accept : "application/json" , Authorization : `token ${ accessToken }` , "Content-Type" : "application/json" , } , method : "PUT" , } ) ; if ( response . status === 409 ) { throw new Conflict ( ) ; } if ( response . status === 404 ) { throw new FileNotFound ( ) ; } if ( response . status !== 200 && response . status !== 201 ) { throw new Error ( `Status: ${ response . statusText }` ) ; } } export async function rm ( accessToken , repo , filename , sha ) { const response = await fetch ( `https://api.github.com/repos/${ repo }/contents/${ filename }` , { body : JSON . stringify ( { branch : await getDefaultBranch ( accessToken , repo ) , message : `Saved via ${ process . env . HOMEPAGE || "Hacklily" }` , sha : sha ? sha : undefined , } ) , headers : { Accept : "application/json" , Authorization : `token ${ accessToken }` , "Content-Type" : "application/json" , } , method : "DELETE" , } ) ; if ( response . status === 409 ) { throw new Conflict ( ) ; } if ( response . status !== 200 ) { throw new Error ( `Status: ${ response . statusText }` ) ; } }