Static site hosting via tangled
1import PagesService from "./pages-service.js"; 2import express from "express"; 3import fs from "fs"; 4import yargs from "yargs"; 5 6class Config { 7 constructor({ site, sites, subdomainOffset }) { 8 this.site = site; 9 this.sites = sites || []; 10 this.subdomainOffset = subdomainOffset; 11 } 12 13 static fromFile(filepath) { 14 const config = JSON.parse(fs.readFileSync(filepath, "utf8")); 15 return new Config(config); 16 } 17} 18 19class Server { 20 constructor(config) { 21 this.config = config; 22 this.app = express(); 23 24 if (config.subdomainOffset) { 25 this.app.set("subdomain offset", config.subdomainOffset); 26 } 27 28 this.app.get("/{*any}", async (req, res) => { 29 const subdomain = req.subdomains.at(-1); 30 // Single site mode 31 if (!subdomain) { 32 if (this.config.site) { 33 return this.handleSiteRequest(req, res, this.config.site); 34 } else { 35 return res.status(200).send("Tangled pages is running!"); 36 } 37 } 38 // Multi site mode 39 const matchingSite = this.config.sites.find( 40 (site) => site.subdomain === subdomain 41 ); 42 if (matchingSite) { 43 await this.handleSiteRequest(req, res, matchingSite); 44 } else { 45 console.log("No matching site found for subdomain", subdomain); 46 return res.status(404).send("Not Found"); 47 } 48 }); 49 } 50 51 async handleSiteRequest(req, res, site) { 52 const route = req.path; 53 const pagesService = new PagesService({ 54 domain: site.knotDomain, 55 ownerDid: site.ownerDid, 56 repoName: site.repoName, 57 branch: site.branch, 58 baseDir: site.baseDir, 59 notFoundFilepath: site.notFoundFilepath, 60 }); 61 const { status, content, contentType } = await pagesService.getPage(route); 62 res.status(status).set("Content-Type", contentType).send(content); 63 } 64 65 async start() { 66 this.app.listen(3000, () => { 67 console.log("Server is running on port 3000"); 68 }); 69 this.app.on("error", (error) => { 70 console.error("Server error:", error); 71 }); 72 } 73} 74 75async function main() { 76 const args = yargs(process.argv.slice(2)).parse(); 77 const configFilepath = args.config || "config.json"; 78 const config = Config.fromFile(configFilepath); 79 const server = new Server(config); 80 await server.start(); 81} 82 83main();