Files
vue-journal-layer/testing/nuxt-server.mjs
Jakub Zych e0cc87118c fix: keep the site cache purge token out of the page payload (NUXT_CACHE_PURGE_TOKEN)
nuxt-site-config copies every NUXT_SITE_* variable into the public site
config, so NUXT_SITE_CACHE_PURGE_TOKEN reached every page's payload as
cachePurgeToken (and NUXT_SITE_CACHE_ALLOW_PROXIED as cacheAllowProxied).

- The purge settings move to runtimeConfig cachePurge.token
  (NUXT_CACHE_PURGE_TOKEN) and cachePurge.allowProxied
  (NUXT_CACHE_PURGE_ALLOW_PROXIED), outside that prefix.
- The old siteCache.* names keep working for one release: a non-empty
  new token wins, either allowProxied flag turns it on, and one
  deprecation warning per process names the variables (never a value).
- The shared Nitro plugin server/plugins/site-cache-purge.ts strips
  cachePurgeToken and cacheAllowProxied from nuxt-site-config's stack on
  site-config:init, so a site on the old names leaks nothing either; it
  does nothing without nuxt-site-config.
- The shared lib, route and plugin and tests/sitePurge.test.ts are
  byte-identical in vue-journal-layer, vue-menu-layer and vue-faq-layer,
  with three sha256 pins.
- README: new names, the deprecation, the stripping and the advice to
  rotate a token ever set under the old name.
2026-10-20 20:49:34 +02:00

75 lines
2.6 KiB
JavaScript

// Boots a built Nuxt server (`<outputDir>/server/index.mjs`) on 127.0.0.1
// against a given Journal API base and waits until it answers HTTP.
// Plain .mjs with JSDoc types so it runs from node_modules unchanged.
import { spawn } from 'node:child_process'
import { createServer } from 'node:net'
import { existsSync } from 'node:fs'
import { join, resolve } from 'node:path'
/** @returns {Promise<number>} */
function freePort() {
return new Promise((done, fail) => {
const srv = createServer()
srv.once('error', fail)
srv.listen(0, '127.0.0.1', () => {
const { port } = /** @type {import('node:net').AddressInfo} */ (srv.address())
srv.close(() => done(port))
})
})
}
/**
* The returned `output()` gives the server's captured stdout and stderr so
* far, for checks on what the server logged.
*
* @param {{ outputDir: string, apiBase: string, port?: number, env?: Record<string, string>, timeoutMs?: number }} opts
* @returns {Promise<{ url: string, close: () => Promise<void>, output: () => string }>}
*/
export async function startNuxtServer({ outputDir, apiBase, port = 0, env = {}, timeoutMs = 30000 }) {
const entry = join(resolve(outputDir), 'server', 'index.mjs')
if (!existsSync(entry)) throw new Error(`nuxt-server: ${entry} does not exist; build first`)
const listenPort = port || (await freePort())
const url = `http://127.0.0.1:${listenPort}`
const child = spawn(process.execPath, [entry], {
env: {
...process.env,
NODE_ENV: 'production',
NITRO_HOST: '127.0.0.1',
NITRO_PORT: String(listenPort),
NUXT_JOURNAL_API_BASE: apiBase,
...env,
},
stdio: ['ignore', 'pipe', 'pipe'],
})
let log = ''
child.stdout.on('data', (b) => (log += b))
child.stderr.on('data', (b) => (log += b))
let exited = false
child.once('exit', () => (exited = true))
const close = () =>
new Promise((/** @type {(v?: void) => void} */ done) => {
if (exited) return done()
child.once('exit', () => done())
child.kill('SIGTERM')
setTimeout(() => {
if (!exited) child.kill('SIGKILL')
}, 5000).unref()
})
const deadline = Date.now() + timeoutMs
while (Date.now() < deadline) {
if (exited) throw new Error(`nuxt-server: server exited before answering\n${log}`)
try {
await fetch(url + '/', { redirect: 'manual', signal: AbortSignal.timeout(2000) })
return { url, close, output: () => log }
} catch {
await new Promise((r) => setTimeout(r, 200))
}
}
await close()
throw new Error(`nuxt-server: no answer on ${url} within ${timeoutMs} ms\n${log}`)
}