'use strict'; const path = require('node:path'); const fs = require('node:fs'); function physical(file) { if (fs.existsSync(file)) return fs.realpathSync(file); const parent = path.dirname(file); return parent === file ? file : path.join(physical(parent), path.basename(file)); } function inside(file, parent) { if (process.platform === 'win32') { file = file.toLowerCase(); parent = parent.toLowerCase(); } return file === parent || file.startsWith(parent + path.sep); } // One immutable entry mode per process. Never infer a channel from client input. module.exports = function entryConfig(env, root) { const mode = env.JUZI_ENTRY_MODE || 'state'; if (!['state', 'rednote'].includes(mode)) throw Error('Unsupported JUZI_ENTRY_MODE'); const rednote = mode === 'rednote'; const dataRoot = env.JUZI_DATA_ROOT ? path.resolve(env.JUZI_DATA_ROOT) : path.join(root, 'data'); if (rednote) { const protectedRoots = [root, env.JUZI_PROTECTED_DATA_ROOT].filter(Boolean).map(p => physical(path.resolve(p))); if (!env.JUZI_DATA_ROOT || protectedRoots.some(p => inside(physical(dataRoot), p))) { throw Error('Rednote requires its own JUZI_DATA_ROOT outside the shared h5 directory and protected data'); } const base = new URL(env.PUBLIC_BASE_URL || ''); if (!['http:', 'https:'].includes(base.protocol) || base.pathname !== '/rednote/' || base.search || base.hash || base.username || base.password || (env.NODE_ENV === 'production' && base.protocol !== 'https:')) { throw Error('Rednote PUBLIC_BASE_URL must end with /rednote/'); } } return { mode, rednote, dataRoot, channel: rednote ? 'rednote' : 'h5', client: { mode, persistentBrowser: rednote } }; };