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 // Single site mode 30 if (this.config.site) { 31 return this.handleSiteRequest(req, res, this.config.site); 32 } 33 // Multi site mode 34 const subdomain = req.subdomains.at(-1); 35 if (!subdomain) { 36 return res.status(200).send("Tangled pages is running!"); 37 } 38 const matchingSite = this.config.sites.find( 39 (site) => site.subdomain === subdomain 40 ); 41 if (matchingSite) { 42 await this.handleSiteRequest(req, res, matchingSite); 43 } else { 44 console.log("No matching site found for subdomain", subdomain); 45 return res.status(404).send("Not Found"); 46 } 47 }); 48 } 49 50 async handleSiteRequest(req, res, site) { 51 const route = req.path; 52 const pagesService = new PagesService({ 53 domain: site.knotDomain, 54 ownerDid: site.ownerDid, 55 repoName: site.repoName, 56 branch: site.branch, 57 baseDir: site.baseDir, 58 notFoundFilepath: site.notFoundFilepath, 59 }); 60 const { status, content, contentType } = await pagesService.getPage(route); 61 res.status(status).set("Content-Type", contentType).send(content); 62 } 63 64 async start() { 65 this.app.listen(3000, () => { 66 console.log("Server is running on port 3000"); 67 }); 68 this.app.on("error", (error) => { 69 console.error("Server error:", error); 70 }); 71 } 72} 73 74async function main() { 75 const args = yargs(process.argv.slice(2)).parse(); 76 const configFilepath = args.config || "config.json"; 77 const config = Config.fromFile(configFilepath); 78 const server = new Server(config); 79 await server.start(); 80} 81 82main();