{
  "version": 3,
  "sources": ["../../../../src/packages/store-connection-manager/index.ts"],
  "sourcesContent": ["// cspell:ignore noent\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { packageManager } from '../cli-meta/index.ts';\nimport type { Config } from '../config/index.ts';\nimport { PnpmError } from '../error/index.ts';\nimport { logger } from '../logger/index.ts';\nimport type { PackageResponse } from '../package-store/index.ts';\nimport type { StoreServerController } from '../server/index.ts';\nimport { getStorePath } from '../store-path/index.ts';\nimport delay from 'delay';\nimport {\n  createNewStoreController,\n  createNewServerStoreController,\n  type CreateNewStoreControllerOptions,\n} from './createNewStoreController.ts';\nimport { runServerInBackground } from './runServerInBackground.ts';\nimport { serverConnectionInfoDir } from './serverConnectionInfoDir.ts';\nimport { connectStoreManagerController } from '../server/connectStoreController.ts';\n\nexport {\n  serverConnectionInfoDir,\n  createNewStoreController,\n  createNewServerStoreController,\n};\n\nexport type CreateStoreControllerOptions = Omit<\n  CreateNewStoreControllerOptions,\n  'storeDir'\n> &\n  Pick<\n    Config,\n    | 'storeDir'\n    | 'dir'\n    | 'pnpmHomeDir'\n    | 'useRunningStoreServer'\n    | 'useStoreServer'\n    | 'workspaceDir'\n  >;\n\nexport async function createOrConnectStoreController(\n  opts: CreateStoreControllerOptions\n): Promise<{\n  ctrl: StoreServerController<\n    PackageResponse,\n    PackageResponse,\n    {\n      isBuilt: boolean;\n      importMethod?: string | undefined;\n    }\n  >;\n  dir: string;\n}> {\n  const storeDir = await getStorePath({\n    pkgRoot: opts.workspaceDir ?? 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  let serverJson = await tryLoadServerJson({\n    serverJsonPath,\n    shouldRetryOnNoent: false,\n  });\n\n  if (serverJson !== null) {\n    if (serverJson.pnpmVersion !== packageManager.version) {\n      logger.warn({\n        message: `The store server runs on pnpm v${serverJson.pnpmVersion}. It is recommended to connect with the same version (current is v${packageManager.version})`,\n        prefix: opts.dir,\n      });\n    }\n\n    logger.info({\n      message:\n        'A store server is running. All store manipulations are delegated to it.',\n      prefix: opts.dir,\n    });\n\n    return {\n      ctrl: await connectStoreManagerController(serverJson.connectionOptions),\n      dir: storeDir,\n    };\n  }\n\n  if (opts.useRunningStoreServer === true) {\n    throw new PnpmError('NO_STORE_SERVER', 'No store server is running.');\n  }\n\n  if (opts.useStoreServer === true) {\n    runServerInBackground(storeDir);\n\n    serverJson = await tryLoadServerJson({\n      serverJsonPath,\n      shouldRetryOnNoent: true,\n    });\n\n    logger.info({\n      message:\n        'A store server has been started. To stop it, use `pnpm server stop`',\n      prefix: opts.dir,\n    });\n\n    const connectionOptions = serverJson?.connectionOptions;\n\n    if (typeof connectionOptions === 'undefined') {\n      throw new Error('Connection options are undefined');\n    }\n\n    return {\n      ctrl: await connectStoreManagerController<{\n        isBuilt: boolean;\n        importMethod?: string | undefined;\n      }>(connectionOptions),\n      dir: storeDir,\n    };\n  }\n\n  return createNewServerStoreController(\n    Object.assign(opts, {\n      storeDir,\n    })\n  );\n}\n\nexport async function tryLoadServerJson(options: {\n  serverJsonPath: string;\n  shouldRetryOnNoent: boolean;\n}): Promise<null | {\n  connectionOptions: {\n    remotePrefix: string;\n  };\n  pid: number;\n  pnpmVersion: string;\n}> {\n  let beforeFirstAttempt = true;\n\n  const startHRTime = process.hrtime();\n\n  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n  while (true) {\n    if (!beforeFirstAttempt) {\n      const elapsedHRTime = process.hrtime(startHRTime);\n      // Time out after 10 seconds of waiting for the server to start, assuming something went wrong.\n      // E.g. server got a SIGTERM or was otherwise abruptly terminated, server has a bug or a third\n      // party is interfering.\n      if (elapsedHRTime[0] >= 10) {\n        // Delete the file in an attempt to recover from this bad state.\n        try {\n          await fs.unlink(options.serverJsonPath);\n          // eslint-disable-next-line @typescript-eslint/no-explicit-any\n        } catch (error: any) {\n          if (error.code !== 'ENOENT') {\n            throw error;\n          }\n          // Either the server.json was manually removed or another process already removed it.\n        }\n\n        return null;\n      }\n\n      // Poll for server startup every 200 milliseconds.\n      await delay(200);\n    }\n\n    beforeFirstAttempt = false;\n\n    let serverJsonStr: string | null;\n\n    try {\n      serverJsonStr = await fs.readFile(options.serverJsonPath, 'utf8');\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    } catch (error: any) {\n      if (error.code !== 'ENOENT') {\n        throw error;\n      }\n\n      if (!options.shouldRetryOnNoent) {\n        return null;\n      }\n\n      continue;\n    }\n\n    let serverJson: {\n      connectionOptions: { remotePrefix: string };\n      pid: number;\n      pnpmVersion: string;\n    } | null;\n\n    try {\n      // TODO: valibot schema\n      serverJson = JSON.parse(serverJsonStr) as {\n        connectionOptions: { remotePrefix: string };\n        pid: number;\n        pnpmVersion: string;\n      };\n\n      // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unused-vars\n    } catch (_error: any) {\n      // Server is starting or server.json was modified by a third party.\n      // We assume the best case and retry.\n      continue;\n    }\n\n    // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition\n    if (serverJson === null) {\n      // Our server should never write null to server.json, even though it is valid json.\n      throw new Error('server.json was modified by a third party');\n    }\n\n    return serverJson;\n  }\n}\n"],
  "mappings": "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",
  "names": []
}
