this repo has no description smallweb.run
smallweb
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 185 lines 5.8 kB view raw
1import { accepts } from "jsr:@std/http@1.0.12/negotiation" 2import { escape } from "jsr:@std/html@1.0.3" 3import { decodeBase64 } from "jsr:@std/encoding@1.0.8/base64" 4 5function cleanStack(str?: string) { 6 if (!str) return undefined; 7 return str 8 .split("\n") 9 .filter( 10 (line) => 11 !line.includes(import.meta.url) && 12 !line.includes("deno_http/00_serve.ts") && 13 !line.includes("core/01_core.js") 14 ) 15 .join("\n"); 16} 17 18function serializeError(e: Error) { 19 return { name: e.name, message: e.message, stack: cleanStack(e.stack) }; 20}; 21 22function respondWithError(request: Request, error: Error) { 23 const e = serializeError(error); 24 if (accepts(request, "text/html")) { 25 return new Response(/* html */`<!DOCTYPE html> 26 <html> 27 <head> 28 <title>Error</title> 29 <style> 30 * { box-sizing: border-box } 31 body { 32 margin: 0; 33 font-family: monospace; 34 min-height: 100vh; 35 display: flex; 36 flex-direction: column; 37 color: black; 38 background-color: white; 39 } 40 div { 41 padding: 0 16px; 42 width: 100%; 43 margin: auto; 44 max-width: 768px; 45 color: inherit; 46 border-left: 0.25em solid #3d444d; 47 border-color: #da3633; 48 } 49 h1 { 50 font-weight: 500; 51 color: #f85149; 52 } 53 pre { 54 margin: 0; 55 padding-bottom: 16px; 56 font-size: 12px; 57 line-height: 1.5; 58 overflow: auto; 59 white-space: pre-wrap; 60 width: 100%; 61 } 62 </style> 63 </head> 64 <body> 65 <div> 66 <h1> 67 ${escape(e.name)} 68 </h1> 69 <pre>${escape(e.stack ?? e.message)}</pre> 70 </div> 71 </body> 72 </html>`, { status: 500, headers: { 'Content-Type': 'text/html' } }); 73 } 74 75 return Response.json( 76 { error: e }, 77 { status: 500, headers: { 'Content-Type': 'application/json' } }, 78 ); 79} 80 81const payload = JSON.parse(Deno.args[0]); 82 83if (!payload || !payload.command) { 84 console.error("Invalid input."); 85 Deno.exit(1); 86} 87 88if (payload.command === "fetch") { 89 Deno.serve( 90 { 91 port: parseInt(payload.port), 92 onListen: () => { 93 // This line will signal that the server is ready to the go 94 console.error("READY"); 95 }, 96 }, 97 async (req) => { 98 try { 99 const mod = await import(payload.entrypoint); 100 if (!mod.default) { 101 return new Response("The app does not provide a default export.", { status: 500 }); 102 } 103 104 if (typeof mod.default !== "object") { 105 return new Response("The app default export must be an object.", { status: 500 }); 106 } 107 if ( 108 !("fetch" in mod.default) || 109 typeof mod.default.fetch !== "function" 110 ) { 111 return new Response("The app default export does not have a fetch method.", { status: 500 }); 112 } 113 114 const handler = mod.default.fetch; 115 // Websocket requests are stateful and should be handled differently 116 if (req.headers.get("upgrade") === "websocket") { 117 const resp = await handler(req); 118 if (!(resp instanceof Response)) { 119 return new Response("Fetch handler must return a Response object.", { status: 500 }); 120 } 121 122 return resp; 123 } 124 125 const url = new URL(req.url); 126 const proto = req.headers.get("x-forwarded-proto"); 127 const host = req.headers.get("x-forwarded-host"); 128 const resp = await handler(new Request(`${proto}://${host}${url.pathname}${url.search}`, { 129 method: req.method, 130 headers: req.headers, 131 body: req.body, 132 })); 133 if (!(resp instanceof Response)) { 134 throw new Error("Fetch handler must return a Response object."); 135 } 136 137 return resp; 138 } catch (e) { 139 return respondWithError(req, e as Error); 140 } 141 }, 142 ); 143} else if (payload.command === "run") { 144 const mod = await import(payload.entrypoint); 145 if (!mod.default || typeof mod.default !== "object") { 146 console.error( 147 "The mod does not provide an object as it's default export.", 148 ); 149 Deno.exit(1); 150 } 151 152 const handler = mod.default; 153 if (!("run" in handler)) { 154 console.error("The mod default export does not have a run function."); 155 Deno.exit(1); 156 } 157 158 if (!(typeof handler.run === "function")) { 159 console.error("The mod default export run property must be a function."); 160 Deno.exit(1); 161 } 162 163 await handler.run(payload.args); 164} else if (payload.command === "email") { 165 const mod = await import(payload.entrypoint); 166 if (!mod.default || typeof mod.default !== "object") { 167 console.error( 168 "The mod does not provide an object as it's default export.", 169 ); 170 Deno.exit(1); 171 } 172 173 const handler = mod.default; 174 if (!("email" in handler)) { 175 console.error("The mod default export does not have a email function."); 176 Deno.exit(1); 177 } 178 179 const data = decodeBase64(payload.msg) 180 const blob = new Blob([data]); 181 await handler.email(blob.stream()); 182} else { 183 console.error("Unknown command: ", payload.command); 184 Deno.exit(1); 185}