<commit_before>require('dotenv').config()

const dev = process.env.NODE_ENV !== 'production'

// initialize elastic-apm if so configured
let apm
if (process.env.APM_SERVER_URL) {
  apm = require('elastic-apm-node').start({
    active: !dev,
    serviceName: process.env.APM_NAME,
    secretToken: process.env.APM_SECRET_TOKEN,
    serverUrl: process.env.APM_SERVER_URL,
  })
}

const IntlPolyfill = require('intl')

const { basename, join } = require('path')
const { readFileSync } = require('fs')
const glob = require('glob')

const accepts = require('accepts')
const cookieParser = require('cookie-parser')
const express = require('express')
const next = require('next')
const compression = require('compression')
const helmet = require('helmet')
const morgan = require('morgan')

// Polyfill Node with `Intl` that has data for all locales.
// See: https://formatjs.io/guides/runtime-environments/#server
Intl.NumberFormat = IntlPolyfill.NumberFormat
Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat

// Specify where the Next.js source files are stored
const APP_DIR = './src'

// Bootstrap a new Next.js application
const app = next({ dev, dir: APP_DIR })
const handle = app.getRequestHandler()

// Get the supported languages by looking for translations in the `lang/` dir.
const languages = glob.sync(`${APP_DIR}/lang/*.json`).map(f => basename(f, '.json'))

const getLocale = (req) => {
  // if a locale cookie was already set, use the locale saved within
  if (req.cookies.locale && languages.includes(req.cookies.locale)) {
    return {
      locale: req.cookies.locale,
    }
  }

  // if the accepts header is set, use its language
  const accept = accepts(req)
  return {
    locale: accept.language(dev ? ['en'] : languages),
    setCookie: true,
  }
}

// We need to expose React Intl's locale data on the request for the user's
// locale. This function will also cache the scripts by lang in memory.
const localeDataCache = new Map()
const getLocaleDataScript = (locale) => {
  const lang = locale.split('-')[0]
  if (!localeDataCache.has(lang)) {
    const localeDataFile = require.resolve(`react-intl/locale-data/${lang}`)
    const localeDataScript = readFileSync(localeDataFile, 'utf8')
    localeDataCache.set(lang, localeDataScript)
  }
  return localeDataCache.get(lang)
}

// We need to load and expose the translations on the request for the user's
// locale. These will only be used in production, in dev the `defaultMessage` in
// each message description in the source code will be used.
const getMessages = locale => require(`${APP_DIR}/lang/${locale}.json`)

// prepare cache to be connected to
let cache
const connectCache = async () => {
  if (cache) {
    return cache
  }

  if (process.env.REDIS_URL) {
    const Redis = require('ioredis')
    cache = new Redis(`redis://${process.env.REDIS_URL}`)
    console.log('[redis] Connected to db 0')
  } else {
    const LRUCache = require('lru-cache')
    cache = new LRUCache({
      max: 100,
      // TODO: this would be nice to set much higher
      // but how would we clean up i.e. /join/someuser when the running session updates?
      maxAge: 1000 * 10, // pages are cached for 10 seconds
    })
  }

  return cache
}

// construct a unique cache key from the request params
const getCacheKey = req => `${req.url}:${req.locale}`

// render a page to html and cache it in the appropriate place
const renderAndCache = async (req, res, pagePath, queryParams, expiration = 60) => {
  const key = getCacheKey(req)

  let cached
  if (process.env.REDIS_URL) {
    cached = await cache.get(key)
  } else {
    cached = cache.get(key)
  }

  // check if the page has already been cached
  // return the cached HTML if this is the case
  if (cached) {
    console.log(`[klicker-react] cache hit: ${key}`)

    res.send(cached)
    return
  }

  // otherwise server-render the page and cache/return it
  console.log(`[klicker-react] cache miss: ${key}`)
  try {
    const html = await app.renderToHTML(req, res, pagePath, queryParams)

    res.send(html)

    // let the cache expire if redis is used
    if (process.env.REDIS_URL) {
      cache.set(key, html, 'EX', expiration)
    } else {
      cache.set(key, html)
    }
  } catch (e) {
    app.renderError(e, req, res, pagePath, queryParams)
  }
}

app
  .prepare()
  .then(() => {
    const server = express()

    connectCache()

    // if the server is behind a proxy, set the APP_PROXY env to true
    // this will make express trust the X-* proxy headers and set corresponding req.ip
    if (process.env.APP_PROXY) {
      server.enable('trust proxy')
    }

    const middleware = [
      // compress using gzip
      compression(),
      // secure the server with helmet
      helmet({
        hsts: false,
      }),
      // enable cookie parsing for the locale cookie
      cookieParser(),
    ]

    // static file serving from public folder
    middleware.push(express.static(join(__dirname, 'public')))

    // activate morgan logging in production
    if (!dev) {
      middleware.push(morgan('combined'))
    }

    server.use(...middleware)

    // prepare page configuration
    const pages = [
      {
        cached: 60 * 10,
        url: '/',
      },
      {
        url: '/user/login',
      },
      {
        url: '/user/registration',
      },
      {<commit_msg>(fix) Don't cache landing page<commit_after>require('dotenv').config()

const dev = process.env.NODE_ENV !== 'production'

// initialize elastic-apm if so configured
let apm
if (process.env.APM_SERVER_URL) {
  apm = require('elastic-apm-node').start({
    active: !dev,
    serviceName: process.env.APM_NAME,
    secretToken: process.env.APM_SECRET_TOKEN,
    serverUrl: process.env.APM_SERVER_URL,
  })
}

const IntlPolyfill = require('intl')

const { basename, join } = require('path')
const { readFileSync } = require('fs')
const glob = require('glob')

const accepts = require('accepts')
const cookieParser = require('cookie-parser')
const express = require('express')
const next = require('next')
const compression = require('compression')
const helmet = require('helmet')
const morgan = require('morgan')

// Polyfill Node with `Intl` that has data for all locales.
// See: https://formatjs.io/guides/runtime-environments/#server
Intl.NumberFormat = IntlPolyfill.NumberFormat
Intl.DateTimeFormat = IntlPolyfill.DateTimeFormat

// Specify where the Next.js source files are stored
const APP_DIR = './src'

// Bootstrap a new Next.js application
const app = next({ dev, dir: APP_DIR })
const handle = app.getRequestHandler()

// Get the supported languages by looking for translations in the `lang/` dir.
const languages = glob.sync(`${APP_DIR}/lang/*.json`).map(f => basename(f, '.json'))

const getLocale = (req) => {
  // if a locale cookie was already set, use the locale saved within
  if (req.cookies.locale && languages.includes(req.cookies.locale)) {
    return {
      locale: req.cookies.locale,
    }
  }

  // if the accepts header is set, use its language
  const accept = accepts(req)
  return {
    locale: accept.language(dev ? ['en'] : languages),
    setCookie: true,
  }
}

// We need to expose React Intl's locale data on the request for the user's
// locale. This function will also cache the scripts by lang in memory.
const localeDataCache = new Map()
const getLocaleDataScript = (locale) => {
  const lang = locale.split('-')[0]
  if (!localeDataCache.has(lang)) {
    const localeDataFile = require.resolve(`react-intl/locale-data/${lang}`)
    const localeDataScript = readFileSync(localeDataFile, 'utf8')
    localeDataCache.set(lang, localeDataScript)
  }
  return localeDataCache.get(lang)
}

// We need to load and expose the translations on the request for the user's
// locale. These will only be used in production, in dev the `defaultMessage` in
// each message description in the source code will be used.
const getMessages = locale => require(`${APP_DIR}/lang/${locale}.json`)

// prepare cache to be connected to
let cache
const connectCache = async () => {
  if (cache) {
    return cache
  }

  if (process.env.REDIS_URL) {
    const Redis = require('ioredis')
    cache = new Redis(`redis://${process.env.REDIS_URL}`)
    console.log('[redis] Connected to db 0')
  } else {
    const LRUCache = require('lru-cache')
    cache = new LRUCache({
      max: 100,
      // TODO: this would be nice to set much higher
      // but how would we clean up i.e. /join/someuser when the running session updates?
      maxAge: 1000 * 10, // pages are cached for 10 seconds
    })
  }

  return cache
}

// construct a unique cache key from the request params
const getCacheKey = req => `${req.url}:${req.locale}`

// render a page to html and cache it in the appropriate place
const renderAndCache = async (req, res, pagePath, queryParams, expiration = 60) => {
  const key = getCacheKey(req)

  let cached
  if (process.env.REDIS_URL) {
    cached = await cache.get(key)
  } else {
    cached = cache.get(key)
  }

  // check if the page has already been cached
  // return the cached HTML if this is the case
  if (cached) {
    console.log(`[klicker-react] cache hit: ${key}`)

    res.send(cached)
    return
  }

  // otherwise server-render the page and cache/return it
  console.log(`[klicker-react] cache miss: ${key}`)
  try {
    const html = await app.renderToHTML(req, res, pagePath, queryParams)

    res.send(html)

    // let the cache expire if redis is used
    if (process.env.REDIS_URL) {
      cache.set(key, html, 'EX', expiration)
    } else {
      cache.set(key, html)
    }
  } catch (e) {
    app.renderError(e, req, res, pagePath, queryParams)
  }
}

app
  .prepare()
  .then(() => {
    const server = express()

    connectCache()

    // if the server is behind a proxy, set the APP_PROXY env to true
    // this will make express trust the X-* proxy headers and set corresponding req.ip
    if (process.env.APP_PROXY) {
      server.enable('trust proxy')
    }

    const middleware = [
      // compress using gzip
      compression(),
      // secure the server with helmet
      helmet({
        hsts: false,
      }),
      // enable cookie parsing for the locale cookie
      cookieParser(),
    ]

    // static file serving from public folder
    middleware.push(express.static(join(__dirname, 'public')))

    // activate morgan logging in production
    if (!dev) {
      middleware.push(morgan('combined'))
    }

    server.use(...middleware)

    // prepare page configuration
    const pages = [
      {
        url: '/',
      },
      {
        url: '/user/login',
      },
      {
        url: '/user/registration',
      },
      {
{'fraction_non_alphanumeric': 0.12398871119473188, 'fraction_numerical': 0.0033866415804327376, 'mean_word_length': 3.0591828942344406, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 19, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3765381', 'n_tokens_mistral': 3320, 'n_tokens_neox': 3232, 'n_words': 1043}