openreader/next.config.ts
Richard R 1bd13c02fe refactor(compute): modularize core contracts and runtime, enable flexible backend resolution
Restructure compute core by extracting job contracts and runtime logic into separate
modules (`contracts.ts`, `local-runtime.ts`) for improved modularity and clearer
API boundaries. Update exports and imports across worker, server, and local
compute backends to use the new modules. Enhance Next.js config to support
dynamic backend selection via build-time constants and aliasing, enabling
seamless switching between local and worker compute modes. Adjust TypeScript
paths and Dockerfile entrypoint to align with the new structure.
2026-05-20 15:07:22 -06:00

111 lines
3.6 KiB
TypeScript

import type { NextConfig } from "next";
import path from "node:path";
const securityHeaders = [
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'X-Frame-Options', value: 'SAMEORIGIN' },
{
key: 'Content-Security-Policy',
value: "frame-ancestors 'self' https://*.huggingface.co https://huggingface.co",
},
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
{
key: 'Strict-Transport-Security',
value: 'max-age=63072000; includeSubDomains; preload',
},
];
const computeModeRaw = (process.env.COMPUTE_MODE || 'local').trim().toLowerCase();
const computeMode = computeModeRaw === 'none' || computeModeRaw === 'worker' || computeModeRaw === 'local'
? computeModeRaw
: 'local';
const computeLocal = computeMode === 'local';
const serverExternalPackages = [
'@napi-rs/canvas',
'ffmpeg-static',
'better-sqlite3',
...(computeLocal ? ['onnxruntime-node', '@huggingface/tokenizers'] : []),
];
const nextConfig: NextConfig = {
output: 'standalone',
async headers() {
return [
{
// Apply security headers to all routes
source: '/(.*)',
headers: securityHeaders,
},
];
},
turbopack: {
resolveAlias: {
canvas: '@napi-rs/canvas',
},
},
transpilePackages: computeLocal ? ['@openreader/compute-core'] : [],
serverExternalPackages,
outputFileTracingIncludes: {
'/api/audiobook': [
'./node_modules/ffmpeg-static/ffmpeg',
],
'/api/audiobook/chapter': [
'./node_modules/ffmpeg-static/ffmpeg',
],
'/api/tts/segments/ensure': [
'./node_modules/ffmpeg-static/ffmpeg',
],
'/api/documents/blob/preview/ensure': [
'./node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs',
],
'/api/documents/blob/preview/presign': [
'./node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs',
],
'/api/documents/blob/preview/fallback': [
'./node_modules/pdfjs-dist/legacy/build/pdf.worker.mjs',
],
},
...(!computeLocal
? {
outputFileTracingExcludes: {
'/*': [
'./node_modules/onnxruntime-node/**/*',
'./node_modules/@huggingface/tokenizers/**/*',
],
},
}
: {}),
webpack: (config, { isServer }) => {
if (isServer) {
// Use runtime require to avoid adding an explicit webpack TS dependency.
const { DefinePlugin } = require('webpack') as { DefinePlugin: new (defs: Record<string, string>) => unknown };
config.plugins = config.plugins || [];
config.plugins.push(
new DefinePlugin({
__OPENREADER_COMPUTE_MODE__: JSON.stringify(computeMode),
}),
);
}
if (isServer && !computeLocal) {
const workerComputeEntry = path.resolve(__dirname, 'src/lib/server/compute/index.worker.ts');
const computeIndexTs = path.resolve(__dirname, 'src/lib/server/compute/index.ts');
const computeIndexNoExt = path.resolve(__dirname, 'src/lib/server/compute/index');
const computeDir = path.resolve(__dirname, 'src/lib/server/compute');
config.resolve.alias = {
...(config.resolve.alias || {}),
'@/lib/server/compute$': workerComputeEntry,
'@/lib/server/compute/index$': workerComputeEntry,
[`${computeIndexTs}$`]: workerComputeEntry,
[`${computeIndexNoExt}$`]: workerComputeEntry,
[`${computeDir}$`]: workerComputeEntry,
'@openreader/compute-core/local-runtime$': false,
'onnxruntime-node$': false,
'@huggingface/tokenizers$': false,
};
}
return config;
},
};
export default nextConfig;