const SettingsService = require('../services/settings'); const fs = require('fs'); const path = require('path'); const { merge } = require('lodash'); const { BASE_URL, BASE_PATH, MOUNT_PATH, STATIC_URL, STATIC_ORIGIN, } = require('../url'); const { RECAPTCHA_PUBLIC, WEBSOCKET_LIVE_URI } = require('../config'); // Grab TALK_CLIENT_* environment variables. const TALK_CLIENT = /^TALK_CLIENT_/i; // TALK_CLIENT_ENV is all the environment keys that are loaded at runtime. const TALK_CLIENT_ENV = Object.keys(process.env) .filter(key => TALK_CLIENT.test(key)) .reduce( (env, key) => { env[key] = process.env[key]; return env; }, { TALK_RECAPTCHA_PUBLIC: RECAPTCHA_PUBLIC, LIVE_URI: WEBSOCKET_LIVE_URI, STATIC_URL, STATIC_ORIGIN, } ); // TEMPLATE_LOCALS stores the static data that is provided as a `text/json` on // to the client from the template. const TEMPLATE_LOCALS = { BASE_URL, BASE_PATH, MOUNT_PATH, STATIC_URL, TALK_CLIENT_ENV, data: TALK_CLIENT_ENV, }; // attachStaticLocals will attach the locals to the response only. const attachStaticLocals = locals => { for (const key in TEMPLATE_LOCALS) { const value = TEMPLATE_LOCALS[key]; locals[key] = value; } }; // MANIFESTS are all the manifests accessible by Talk. const MANIFESTS = ['../dist/manifest.json', '../dist/manifest.embed.json']; // getManifest will retrieve the manifest files and parse the JSON. function getManifest() { return merge( {}, ...MANIFESTS.map(f => fs.readFileSync(path.resolve(__dirname, f), 'utf8') ).map(JSON.parse) ); } /** * resolveFactory is a function that can be used in templates to resolve an * asset from the manifest. In production, the manifest is cached. */ const createResolveFactory = (() => { if (process.env.NODE_ENV === 'production') { // In production, we should attempt to load the manifest early. const manifest = getManifest(); return () => key => `${STATIC_URL}static/${manifest[key]}`; } // In dev mode, we are more forgiving and we always load the // newest version of the manifest. return () => { let manifest = {}; try { manifest = getManifest(); } catch (err) { console.warn(err); } return key => key in manifest ? `${STATIC_URL}static/${manifest[key]}` : ''; }; })(); module.exports = async (req, res, next) => { try { // Attach the custom css url and organization name. const { customCssUrl, organizationName } = await SettingsService.select( 'customCssUrl', 'organizationName' ); res.locals.customCssUrl = customCssUrl; res.locals.organizationName = organizationName; } catch (err) { console.warn(err); } // Always attach the locals. attachStaticLocals(res.locals); // Resolve will help resolving paths to static files // using the manifest. res.locals.resolve = createResolveFactory(); // Forward the request. next(); }; module.exports.attachStaticLocals = attachStaticLocals; module.exports.TEMPLATE_LOCALS = TEMPLATE_LOCALS;