// TODO: add query string functionality to cache const { ssrValidatePath } = require("../config") const { log } = require("../lib/utils") const { ssrRequest } = require("../lib/ssr-server") ;(function () { /** @type {HookResponse} */ // @ts-ignore let response = null const request = context.request() let url = request.query("url") const noCache = request.query("noCache") // add sentry trace id to head const trace_id = context.debug.sentryTraceId() /** * @param {string} content */ function addSentryTrace(content) { return content.replace("", '') } context.response.header("sentry-trace", trace_id) if (url) { // comment will be printed to html later let comment = "" /** @type {Date} */ // @ts-ignore context.ssrCacheValidUntil = null url = url.split("?")[0] comment += "url: " + url if (url && url.length > 1) { url = url.replace(/\/$/, "") } if (url == "/noindex" || !url) { url = "/" // see .htaccess } // check if url is in cache /** @type {Ssr[]} */ // @ts-ignore const cache = !noCache && context.db.find("ssr", { filter: { path: url, }, }) if (cache && cache.length) { const validUntil = cache[0].validUntil ? new Date(cache[0].validUntil.unixMilli()) : null // context.debug.dump("cache validUntil", validUntil) if (!validUntil || validUntil > new Date()) { // context.debug.dump("using cache") // use cache context.response.header("X-SSR-Cache", "true") throw { status: 200, log: false, html: addSentryTrace(cache[0].content), } } else { // cache is invalid, delete it context.response.header("X-SSR-Cache", "invalid") // @ts-ignore context.db.delete("ssr", cache[0].id) } } // validate url let status = 200 let pNorender = false let pNotfound = false const pR = ssrValidatePath(url) if (pR < 0) { pNotfound = true } else if (!pR) { pNorender = true } let head = "" let html = "" let error = "" comment += ", path: " + url let cacheIt = false if (pNorender) { html = "" } else if (pNotfound) { status = 404 html = "404 NOT FOUND" } else { // @ts-ignore context.ssrCache = {} // @ts-ignore context.ssrRequest = ssrRequest // try rendering, if error output plain html try { // include App.svelte and render it // @ts-ignore // console.log("####### RENDERING ", url) const app = require("../lib/app.server") const rendered = app.default.render({ url: url, }) head = rendered.head html = rendered.html // add ssrCache to head, cache is built in ssr.js/apiRequest head += "\n\n" + "" // status from webapp // @ts-ignore if (context.is404) { // console.log("########## 404") status = 404 } else { cacheIt = true } } catch (/** @type {any} */ e) { // save error for later insert into html log(e.message) log(e.stack) error = "error: " + e.message + "\n\n" + e.stack } } // read html template and replace placeholders let tpl = context.fs.readFile("templates/spa.html") tpl = tpl.replace("", head) tpl = tpl.replace("", html) tpl = tpl.replace("", error ? "" : "") tpl = tpl.replace("", comment ? "" : "") // save cache if adviced if (cacheIt && !noCache) { context.db.create("ssr", { // context.debug.dump("ssr", { path: url, content: tpl, // @ts-ignore validUntil: context.ssrCacheValidUntil, }) } // return html throw { status: status, log: false, html: addSentryTrace(tpl), } } else { // only admins are allowed to get without url parameter const auth = context.user.auth() if (!auth || auth.role !== 0) { throw { status: 403, message: "invalid auth", auth: auth, } } } })()