{
  "version": 3,
  "sources": ["../../../../src/packages/plugin-commands-server/start.ts"],
  "sourcesContent": ["// cspell:ignore diable\nimport {\n  close as _close,\n  closeSync,\n  open as _open,\n  promises as fs,\n  unlinkSync,\n  write as _write,\n} from 'node:fs';\nimport { promisify } from 'node:util';\nimport path from 'node:path';\nimport { packageManager } from '../cli-meta/index.ts';\nimport { PnpmError } from '../error/index.ts';\nimport { logger } from '../logger/index.ts';\nimport { type StoreServerHandle, createServer } from '../server/index.ts';\nimport {\n  createNewStoreController,\n  type CreateStoreControllerOptions,\n  serverConnectionInfoDir,\n} from '../store-connection-manager/index.ts';\nimport { getStorePath } from '../store-path/index.ts';\n// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport Diable from '@zkochan/diable';\nimport getPort from 'get-port';\nimport isWindows from 'is-windows';\nimport { onExit } from 'signal-exit';\n\nconst storeServerLogger = logger('store-server');\n\nconst write = promisify(_write);\nconst close = promisify(_close);\nconst open = promisify(_open);\n\nexport async function start(\n  opts: CreateStoreControllerOptions & {\n    background?: boolean | undefined;\n    protocol?: 'auto' | 'tcp' | 'ipc' | undefined;\n    port?: number | undefined;\n    ignoreStopRequests?: boolean | undefined;\n    ignoreUploadRequests?: boolean | undefined;\n  }\n): Promise<void> {\n  if (opts.protocol === 'ipc' && typeof opts.port !== 'undefined') {\n    throw new Error('Port cannot be selected when server communicates via IPC');\n  }\n\n  // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n  if (opts.background === true && !Diable.isDaemon() === true) {\n    Diable();\n  }\n\n  const storeDir = await getStorePath({\n    pkgRoot: opts.dir,\n    storePath: opts.storeDir,\n    pnpmHomeDir: opts.pnpmHomeDir,\n  });\n\n  const connectionInfoDir = serverConnectionInfoDir(storeDir);\n\n  const serverJsonPath = path.join(connectionInfoDir, 'server.json');\n\n  await fs.mkdir(connectionInfoDir, { recursive: true });\n\n  // Open server.json with exclusive write access to ensure only one process can successfully\n  // start the server. Note: NFS does not support exclusive writing, but do we really care?\n  // Source: https://github.com/moxystudio/node-proper-lockfile#user-content-comparison\n  let fd: number | null;\n\n  try {\n    fd = await open(serverJsonPath, 'wx');\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  } catch (error: any) {\n    if (error.code !== 'EEXIST') {\n      throw error;\n    }\n\n    throw new PnpmError(\n      'SERVER_MANIFEST_LOCKED',\n      `Canceling startup of server (pid ${process.pid}) because another process got exclusive access to server.json`\n    );\n  }\n\n  let server: null | StoreServerHandle = null;\n\n  onExit((): void => {\n    if (server !== null) {\n      // Note that server.close returns a Promise, but we cannot wait for it because we may be\n      // inside the 'exit' even of process.\n      server.close();\n    }\n\n    if (fd !== null) {\n      try {\n        closeSync(fd);\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any\n      } catch (error: any) {\n        storeServerLogger.error(\n          error,\n          'Got error while closing file descriptor of server.json, but the process is already exiting'\n        );\n      }\n    }\n\n    try {\n      unlinkSync(serverJsonPath);\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    } catch (error: any) {\n      if (error.code !== 'ENOENT') {\n        storeServerLogger.error(\n          error,\n          'Got error unlinking server.json, but the process is already exiting'\n        );\n      }\n    }\n  });\n\n  const store = await createNewStoreController(\n    Object.assign(opts, {\n      storeDir,\n    })\n  );\n\n  const protocol =\n    opts.protocol ?? (typeof opts.port === 'undefined' ? 'auto' : 'tcp');\n\n  const serverOptions = await getServerOptions(connectionInfoDir, {\n    protocol,\n    port: opts.port,\n  });\n\n  const connectionOptions = {\n    remotePrefix:\n      typeof serverOptions.path === 'undefined'\n        ? `http://${serverOptions.hostname}:${serverOptions.port}`\n        : `http://unix:${serverOptions.path}:`,\n  };\n\n  server = createServer(store.ctrl, {\n    ...serverOptions,\n    ignoreStopRequests: opts.ignoreStopRequests,\n    ignoreUploadRequests: opts.ignoreUploadRequests,\n  });\n\n  // Make sure to populate server.json after the server has started, so clients know that the server is\n  // listening if a server.json with valid JSON content exists.\n  const serverJson = {\n    connectionOptions,\n    pid: process.pid,\n    pnpmVersion: packageManager.version,\n  };\n\n  const serverJsonStr = JSON.stringify(serverJson, undefined, 2); // undefined and 2 are for formatting.\n\n  const serverJsonBuffer = Buffer.from(serverJsonStr, 'utf8');\n\n  // fs.write on NodeJS 4 requires the parameters offset and length to be set:\n  // https://nodejs.org/docs/latest-v4.x/api/fs.html#fs_fs_write_fd_buffer_offset_length_position_callback\n  await write(fd, serverJsonBuffer, 0, serverJsonBuffer.byteLength);\n\n  const fdForClose = fd;\n\n  // Set fd to null so we only attempt to close it once.\n  fd = null;\n\n  await close(fdForClose);\n\n  // Intentionally avoid returning control back to the caller until the server\n  // exits. This defers cleanup operations that should not run before the server\n  // finishes.\n  await server.waitForClose;\n}\n\ntype ServerOptions = {\n  hostname?: string | undefined;\n  port?: number | undefined;\n  path?: string | undefined;\n};\n\nasync function getServerOptions(\n  connectionInfoDir: string,\n  opts: {\n    protocol: 'auto' | 'tcp' | 'ipc';\n    port?: number | undefined;\n  }\n): Promise<ServerOptions> {\n  switch (opts.protocol) {\n    case 'tcp': {\n      return getTcpOptions();\n    }\n\n    case 'ipc': {\n      if (isWindows()) {\n        throw new Error('IPC protocol is not supported on Windows currently');\n      }\n      return getIpcOptions();\n    }\n\n    case 'auto': {\n      if (isWindows()) {\n        return getTcpOptions();\n      }\n      return getIpcOptions();\n    }\n\n    default: {\n      throw new Error(`Protocol ${opts.protocol as string} is not supported`);\n    }\n  }\n\n  async function getTcpOptions() {\n    return {\n      hostname: 'localhost',\n      port: opts.port || (await getPort({ port: 5813 })), // eslint-disable-line\n    };\n  }\n\n  function getIpcOptions(): ServerOptions {\n    return {\n      path: path.join(connectionInfoDir, 'socket'),\n    };\n  }\n}\n"],
  "mappings": "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",
  "names": []
}
