const { ssrValidatePath, ssrAllowedAPIEndpoints } = require("../config") const { obj2str, log } = require("../lib/utils") ;(function () { /** @type {HookResponse} */ var response = null var request = context.request() var url = request.query("url") var noCache = request.query("noCache") // add sentry trace id to head var trace_id = context.debug.sentryTraceId() function addSentryTrace(content) { return content.replace("", '') } context.response.header("sentry-trace", trace_id) if (url) { // comment will be printed to html later var comment = "" 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 var cache = !noCache && context.db.find("ssr", { filter: { path: url, }, }) if (cache && cache.length) { // use cache throw { status: 200, log: false, html: addSentryTrace(cache[0].content), } } // validate url var status = 200 var pNorender = false var pNotfound = false var pR = ssrValidatePath(url) if (pR < 0) { pNotfound = true } else if (!pR) { pNorender = true } var head = "" var html = "" var error = "" comment += ", path: " + url var cacheIt = false if (pNorender) { html = "" } else if (pNotfound) { status = 404 html = "404 NOT FOUND" } else { // try rendering, if error output plain html try { // @ts-ignore context.ssrCache = {} // @ts-ignore context.ssrFetch = function (endpoint, options) { var data if (ssrAllowedAPIEndpoints.indexOf(endpoint) > -1) { var _options = Object.assign({}, options) if (_options.sort) _options.sort = [_options.sort] try { /*console.log( "SSR", endpoint, JSON.stringify(_options) )*/ var goSlice = context.db.find(endpoint, _options || {}) // need to deep copy, so shift and delete on pure js is possible data = JSON.parse(JSON.stringify(goSlice)) } catch (e) { console.log("ERROR", JSON.stringify(e)) data = [] } } else { console.log("SSR forbidden", endpoint) data = [] } var count = (data && data.length) || 0 if (options && count == options.limit) { // read count from db count = context.db.count(endpoint, _options || {}) } var r = { data: data, count: count } // @ts-ignore context.ssrCache[obj2str({ endpoint: endpoint, options: options })] = r return r } // include App.svelte and render it // @ts-ignore var app = require("../lib/app.server") var rendered = app.default.render({ url: url, }) head = rendered.head html = rendered.html // add ssrCache to head head += "\n\n" + "" // status from webapp // @ts-ignore if (context.is404) { status = 404 } else { cacheIt = true } } catch (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 var 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", { path: url, content: tpl, }) } // return html throw { status: status, log: false, html: addSentryTrace(tpl), } } else { // only admins are allowed to get without url parameter var auth = context.user.auth() if (!auth || auth.role !== 0) { throw { status: 403, message: "invalid auth", auth: auth, } } } })()