"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.startServer = void 0; const bundler_1 = require("@remotion/bundler"); const renderer_1 = require("@remotion/renderer"); const node_http_1 = __importDefault(require("node:http")); const detect_remotion_server_1 = require("../detect-remotion-server"); const routes_1 = require("../routes"); const dev_middleware_1 = require("./dev-middleware"); const hot_middleware_1 = require("./hot-middleware"); const live_events_1 = require("./live-events"); const startServer = async (options) => { var _a, _b, _c; const desiredPort = (_b = (_a = options === null || options === void 0 ? void 0 : options.port) !== null && _a !== void 0 ? _a : (process.env.PORT ? Number(process.env.PORT) : undefined)) !== null && _b !== void 0 ? _b : undefined; const portConfig = renderer_1.RenderInternals.getPortConfig(options.forceIPv4); const onPortUnavailable = options.forceNew ? undefined : async (port) => { const detection = await (0, detect_remotion_server_1.detectRemotionServer)({ port, cwd: options.remotionRoot, hostname: portConfig.hostsToTry[0], }); return detection.type === 'match' ? 'stop' : 'continue'; }; const [, config] = await bundler_1.BundlerInternals.webpackConfig({ entry: options.entry, userDefinedComponent: options.userDefinedComponent, outDir: null, environment: 'development', webpackOverride: options === null || options === void 0 ? void 0 : options.webpackOverride, maxTimelineTracks: (_c = options === null || options === void 0 ? void 0 : options.maxTimelineTracks) !== null && _c !== void 0 ? _c : null, remotionRoot: options.remotionRoot, keyboardShortcutsEnabled: options.keyboardShortcutsEnabled, experimentalClientSideRenderingEnabled: options.experimentalClientSideRenderingEnabled, poll: options.poll, bufferStateDelayInMilliseconds: options.bufferStateDelayInMilliseconds, askAIEnabled: options.askAIEnabled, }); const compiler = (0, bundler_1.webpack)(config); const wdmMiddleware = (0, dev_middleware_1.wdm)(compiler, options.logLevel); const whm = (0, hot_middleware_1.webpackHotMiddleware)(compiler, options.logLevel); const liveEventsServer = (0, live_events_1.makeLiveEventsRouter)(options.logLevel); const server = node_http_1.default.createServer((request, response) => { if (options.enableCrossSiteIsolation) { response.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); response.setHeader('Cross-Origin-Embedder-Policy', 'require-corp'); } new Promise((resolve) => { wdmMiddleware(request, response, () => { resolve(); }); }) .then(() => { return new Promise((resolve) => { whm(request, response, () => { resolve(); }); }); }) .then(() => { return (0, routes_1.handleRoutes)({ staticHash: options.staticHash, staticHashPrefix: options.staticHashPrefix, outputHash: options.outputHash, outputHashPrefix: options.outputHashPrefix, request: request, response, liveEventsServer, getCurrentInputProps: options.getCurrentInputProps, getEnvVariables: options.getEnvVariables, remotionRoot: options.remotionRoot, entryPoint: options.userDefinedComponent, publicDir: options.publicDir, logLevel: options.logLevel, getRenderQueue: options.getRenderQueue, getRenderDefaults: options.getRenderDefaults, numberOfAudioTags: options.numberOfAudioTags, queueMethods: options.queueMethods, gitSource: options.gitSource, binariesDirectory: options.binariesDirectory, audioLatencyHint: options.audioLatencyHint, enableCrossSiteIsolation: options.enableCrossSiteIsolation, }); }) .catch((err) => { renderer_1.RenderInternals.Log.error({ indent: false, logLevel: options.logLevel }, `Error while calling ${request.url}`, err); if (!response.headersSent) { response.setHeader('content-type', 'application/json'); response.writeHead(500); } if (!response.writableEnded) { response.end(JSON.stringify({ err: err.message, })); } }); }); const maxTries = 5; for (let i = 0; i < maxTries; i++) { try { const { port, unlockPort, didUsePort } = await renderer_1.RenderInternals.getDesiredPort({ desiredPort, from: 3000, to: 3100, hostsToTry: portConfig.hostsToTry, onPortUnavailable, }); if (didUsePort) { unlockPort(); await Promise.all([ new Promise((resolve) => { server.close(() => resolve()); }), new Promise((resolve) => { compiler.close(() => resolve()); }), ]); return { type: 'already-running', port, }; } const selectedPort = await new Promise((resolve, reject) => { renderer_1.RenderInternals.Log.verbose({ indent: false, logLevel: options.logLevel }, `Binding server to host ${portConfig.host}, port ${port}`); server.listen({ port, host: portConfig.host, }); server.on('listening', () => { resolve(port); return unlockPort(); }); server.on('error', (err) => { reject(err); }); }); return { type: 'started', port: selectedPort, liveEventsServer, close: async () => { server.closeAllConnections(); await Promise.all([ new Promise((resolve) => { server.close(() => { resolve(); }); }), new Promise((resolve) => { compiler.close(() => { resolve(); }); }), ]); }, }; } catch (err) { if (!(err instanceof Error)) { throw err; } const codedError = err; if (codedError.code === 'EADDRINUSE') { renderer_1.RenderInternals.Log.error({ indent: false, logLevel: options.logLevel }, `Port ${codedError.port} is already in use. Trying another port...`); } else { throw err; } } } throw new Error(`Tried ${maxTries} times to find a free port. Giving up.`); }; exports.startServer = startServer;