2026-07-31 12:51:15 +03:00
|
|
|
import { recordStartupPerformance } from './startup-performance.js';
|
|
|
|
|
|
2026-03-31 18:47:00 +03:00
|
|
|
export const createStartupPipelineRuntime = (dependencies) => {
|
|
|
|
|
const {
|
|
|
|
|
createTerminalRuntime,
|
2026-07-04 02:48:07 +03:00
|
|
|
createDictationRuntime,
|
2026-04-17 16:07:26 +08:00
|
|
|
createMessageStreamWsRuntime,
|
2026-03-31 18:47:00 +03:00
|
|
|
createServerStartupRuntime,
|
|
|
|
|
} = dependencies;
|
|
|
|
|
|
|
|
|
|
const run = async (options) => {
|
2026-07-31 12:51:15 +03:00
|
|
|
const pipelineStartedAt = performance.now();
|
|
|
|
|
recordStartupPerformance('web.pipeline.start');
|
2026-03-31 18:47:00 +03:00
|
|
|
const {
|
|
|
|
|
app,
|
|
|
|
|
server,
|
|
|
|
|
express,
|
|
|
|
|
fs,
|
|
|
|
|
path,
|
|
|
|
|
uiAuthController,
|
|
|
|
|
buildAugmentedPath,
|
|
|
|
|
searchPathFor,
|
|
|
|
|
isExecutable,
|
|
|
|
|
isRequestOriginAllowed,
|
|
|
|
|
rejectWebSocketUpgrade,
|
2026-04-17 16:07:26 +08:00
|
|
|
buildOpenCodeUrl,
|
|
|
|
|
getOpenCodeAuthHeaders,
|
2026-04-24 11:58:16 +03:00
|
|
|
globalEventHub,
|
2026-04-17 16:07:26 +08:00
|
|
|
processForwardedEventPayload,
|
|
|
|
|
messageStreamWsClients,
|
2026-04-17 23:48:39 +08:00
|
|
|
triggerHealthCheck,
|
2026-05-01 04:57:31 -07:00
|
|
|
upstreamStallTimeoutMs,
|
2026-03-31 18:47:00 +03:00
|
|
|
terminalHeartbeatIntervalMs,
|
|
|
|
|
terminalRebindWindowMs,
|
|
|
|
|
terminalMaxRebindsPerWindow,
|
|
|
|
|
setupProxy,
|
|
|
|
|
scheduleOpenCodeApiDetection,
|
|
|
|
|
bootstrapOpenCodeAtStartup,
|
|
|
|
|
staticRoutesRuntime,
|
|
|
|
|
process,
|
|
|
|
|
crypto,
|
|
|
|
|
normalizeTunnelBootstrapTtlMs,
|
|
|
|
|
readSettingsFromDiskMigrated,
|
|
|
|
|
tunnelAuthController,
|
|
|
|
|
startTunnelWithNormalizedRequest,
|
|
|
|
|
gracefulShutdown,
|
|
|
|
|
getSignalsAttached,
|
|
|
|
|
setSignalsAttached,
|
|
|
|
|
syncToHmrState,
|
|
|
|
|
TUNNEL_MODE_QUICK,
|
|
|
|
|
TUNNEL_MODE_MANAGED_LOCAL,
|
|
|
|
|
TUNNEL_MODE_MANAGED_REMOTE,
|
|
|
|
|
host,
|
|
|
|
|
port,
|
|
|
|
|
startupTunnelRequest,
|
|
|
|
|
onTunnelReady,
|
|
|
|
|
tunnelRuntimeContext,
|
|
|
|
|
attachSignals,
|
2026-06-02 00:43:05 +03:00
|
|
|
apiOnly,
|
2026-07-04 02:48:07 +03:00
|
|
|
dictationModelsDir,
|
2026-03-31 18:47:00 +03:00
|
|
|
} = options;
|
|
|
|
|
|
|
|
|
|
const terminalRuntime = createTerminalRuntime({
|
|
|
|
|
app,
|
|
|
|
|
server,
|
|
|
|
|
express,
|
|
|
|
|
fs,
|
|
|
|
|
path,
|
|
|
|
|
uiAuthController,
|
|
|
|
|
buildAugmentedPath,
|
|
|
|
|
searchPathFor,
|
|
|
|
|
isExecutable,
|
|
|
|
|
isRequestOriginAllowed,
|
|
|
|
|
rejectWebSocketUpgrade,
|
|
|
|
|
TERMINAL_INPUT_WS_HEARTBEAT_INTERVAL_MS: terminalHeartbeatIntervalMs,
|
|
|
|
|
TERMINAL_INPUT_WS_REBIND_WINDOW_MS: terminalRebindWindowMs,
|
|
|
|
|
TERMINAL_INPUT_WS_MAX_REBINDS_PER_WINDOW: terminalMaxRebindsPerWindow,
|
|
|
|
|
});
|
|
|
|
|
|
2026-07-04 02:48:07 +03:00
|
|
|
const dictationRuntime = createDictationRuntime({
|
|
|
|
|
app,
|
|
|
|
|
server,
|
|
|
|
|
express,
|
|
|
|
|
uiAuthController,
|
|
|
|
|
isRequestOriginAllowed,
|
|
|
|
|
rejectWebSocketUpgrade,
|
|
|
|
|
modelsDir: dictationModelsDir,
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-17 16:07:26 +08:00
|
|
|
const messageStreamRuntime = createMessageStreamWsRuntime({
|
|
|
|
|
server,
|
|
|
|
|
uiAuthController,
|
|
|
|
|
isRequestOriginAllowed,
|
|
|
|
|
rejectWebSocketUpgrade,
|
|
|
|
|
buildOpenCodeUrl,
|
|
|
|
|
getOpenCodeAuthHeaders,
|
2026-04-24 11:58:16 +03:00
|
|
|
globalEventHub,
|
2026-04-17 16:07:26 +08:00
|
|
|
processForwardedEventPayload,
|
|
|
|
|
wsClients: messageStreamWsClients,
|
2026-04-17 23:48:39 +08:00
|
|
|
triggerHealthCheck,
|
2026-05-01 04:57:31 -07:00
|
|
|
upstreamStallTimeoutMs,
|
2026-04-17 16:07:26 +08:00
|
|
|
});
|
|
|
|
|
|
2026-03-31 18:47:00 +03:00
|
|
|
setupProxy(app);
|
|
|
|
|
|
2026-06-02 00:43:05 +03:00
|
|
|
if (apiOnly) {
|
|
|
|
|
staticRoutesRuntime.registerApiOnlyFallbackRoutes(app);
|
|
|
|
|
} else {
|
|
|
|
|
staticRoutesRuntime.registerStaticRoutes(app);
|
|
|
|
|
}
|
2026-03-31 18:47:00 +03:00
|
|
|
|
|
|
|
|
const serverStartupRuntime = createServerStartupRuntime({
|
|
|
|
|
process,
|
|
|
|
|
crypto,
|
|
|
|
|
server,
|
|
|
|
|
normalizeTunnelBootstrapTtlMs,
|
|
|
|
|
readSettingsFromDiskMigrated,
|
|
|
|
|
tunnelAuthController,
|
|
|
|
|
startTunnelWithNormalizedRequest,
|
|
|
|
|
gracefulShutdown,
|
|
|
|
|
getSignalsAttached,
|
|
|
|
|
setSignalsAttached,
|
|
|
|
|
syncToHmrState,
|
|
|
|
|
TUNNEL_MODE_QUICK,
|
|
|
|
|
TUNNEL_MODE_MANAGED_LOCAL,
|
|
|
|
|
TUNNEL_MODE_MANAGED_REMOTE,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const bindHost = serverStartupRuntime.resolveBindHost(host);
|
|
|
|
|
const startupResult = await serverStartupRuntime.startListeningAndMaybeTunnel({
|
|
|
|
|
port,
|
|
|
|
|
bindHost,
|
|
|
|
|
startupTunnelRequest,
|
|
|
|
|
onTunnelReady,
|
|
|
|
|
});
|
2026-07-31 12:51:15 +03:00
|
|
|
recordStartupPerformance('web.listener.ready', {
|
|
|
|
|
durationMs: performance.now() - pipelineStartedAt,
|
|
|
|
|
});
|
2026-03-31 18:47:00 +03:00
|
|
|
tunnelRuntimeContext.setActivePort(startupResult.activePort);
|
2026-07-24 21:54:28 +03:00
|
|
|
scheduleOpenCodeApiDetection();
|
|
|
|
|
void bootstrapOpenCodeAtStartup();
|
2026-03-31 18:47:00 +03:00
|
|
|
|
|
|
|
|
serverStartupRuntime.attachProcessHandlers({ attachSignals });
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
terminalRuntime,
|
2026-07-04 02:48:07 +03:00
|
|
|
dictationRuntime,
|
2026-04-17 16:07:26 +08:00
|
|
|
messageStreamRuntime,
|
2026-03-31 18:47:00 +03:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
run,
|
|
|
|
|
};
|
|
|
|
|
};
|