async function startServer(options) {
  const { config } = options

  const context = {
    type: 'serverContext',
    plugin: {},
    config,
    eventbus: new EventBus(),
    processManager: new ProcessManager(),
  }
  /** @type {import('@home-gallery/types').TGalleryPluginManager} */
  const pluginManager = await createPluginManager(options.config, context)
  context.pluginManager = pluginManager
  context.executeQuery = createQueryExecutor(pluginManager)

  const { app, initDatabase } = createApp(context)

  return new Promise((resolve, reject) => {
    const { key, cert, port, host } = config.server
    const server = createServer(key, cert, app);
    server.listen(port, host)
      .on('error', err => {
        if (err.code === 'EADDRINUSE') {
          log.error(`Listening port ${port} is already in use!`);
        }
        reject(err)
      })
      .on('listening', () => resolve(server))
    }).then(async server => {
      const { importSources, watchSources, openBrowser } = config.server
      const url = serverUrl(config)
      log.info(`Your own Home Gallery is running at ${url}`);
      initDatabase();
      if (importSources) {
        const args = 'run import --initial --update'.split(' ');
        if (watchSources) {
          args.push('--watch')
        }
        const watcher = spawnCli(args, getConfigEnv(options))
        context.processManager.addProcess(watcher, 15 * 1000)
      }
      if (openBrowser) {
        log.debug(`Open browser with url ${url}`)
        await open(url)
      }
      return [server, () => shutdown(server, context.processManager)]
    })

}
@type {import('@home-gallery/types').TQueryPlugin[]}