Static site hosting via tangled
1import { 2 getContentTypeForFilename, 3 trimLeadingSlash, 4 extname, 5 joinurl, 6} from "./helpers.js"; 7import { KnotClient } from "./knot-client.js"; 8 9export class PagesService { 10 constructor({ 11 knotDomain, 12 ownerDid, 13 repoName, 14 branch = "main", 15 baseDir = "/", 16 notFoundFilepath = null, 17 }) { 18 this.knotDomain = knotDomain; 19 this.ownerDid = ownerDid; 20 this.repoName = repoName; 21 this.branch = branch; 22 this.baseDir = baseDir; 23 this.notFoundFilepath = notFoundFilepath; 24 this.client = new KnotClient({ 25 domain: knotDomain, 26 ownerDid, 27 repoName, 28 branch, 29 }); 30 } 31 32 async getFileContent(filename) { 33 let content = null; 34 const blob = await this.client.getBlob(filename); 35 if (blob.is_binary) { 36 content = await this.client.getRaw(filename); 37 } else { 38 content = blob.contents; 39 } 40 return content; 41 } 42 43 async getPage(route) { 44 let filePath = route; 45 const extension = extname(filePath); 46 if (!extension) { 47 filePath = joinurl(filePath, "index.html"); 48 } 49 const fullPath = joinurl(this.baseDir, trimLeadingSlash(filePath)); 50 const content = await this.getFileContent(fullPath); 51 if (!content) { 52 return this.get404(); 53 } 54 return { 55 status: 200, 56 content, 57 contentType: getContentTypeForFilename(fullPath), 58 }; 59 } 60 61 async get404() { 62 if (this.notFoundFilepath) { 63 const content = await this.getFileContent(this.notFoundFilepath); 64 if (!content) { 65 console.warn("'Not found' file not found", this.notFoundFilepath); 66 return { status: 404, content: "Not Found", contentType: "text/plain" }; 67 } 68 return { 69 status: 404, 70 content, 71 contentType: getContentTypeForFilename(this.notFoundFilepath), 72 }; 73 } 74 return { status: 404, content: "Not Found", contentType: "text/plain" }; 75 } 76}