createDirectConnectSession.ts 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /* eslint-disable eslint-plugin-n/no-unsupported-features/node-builtins */
  2. import { errorMessage } from '../utils/errors.js'
  3. import { jsonStringify } from '../utils/slowOperations.js'
  4. import type { DirectConnectConfig } from './directConnectManager.js'
  5. import { connectResponseSchema } from './types.js'
  6. /**
  7. * Errors thrown by createDirectConnectSession when the connection fails.
  8. */
  9. export class DirectConnectError extends Error {
  10. constructor(message: string) {
  11. super(message)
  12. this.name = 'DirectConnectError'
  13. }
  14. }
  15. /**
  16. * Create a session on a direct-connect server.
  17. *
  18. * Posts to `${serverUrl}/sessions`, validates the response, and returns
  19. * a DirectConnectConfig ready for use by the REPL or headless runner.
  20. *
  21. * Throws DirectConnectError on network, HTTP, or response-parsing failures.
  22. */
  23. export async function createDirectConnectSession({
  24. serverUrl,
  25. authToken,
  26. cwd,
  27. dangerouslySkipPermissions,
  28. }: {
  29. serverUrl: string
  30. authToken?: string
  31. cwd: string
  32. dangerouslySkipPermissions?: boolean
  33. }): Promise<{
  34. config: DirectConnectConfig
  35. workDir?: string
  36. }> {
  37. const headers: Record<string, string> = {
  38. 'content-type': 'application/json',
  39. }
  40. if (authToken) {
  41. headers['authorization'] = `Bearer ${authToken}`
  42. }
  43. let resp: Response
  44. try {
  45. resp = await fetch(`${serverUrl}/sessions`, {
  46. method: 'POST',
  47. headers,
  48. body: jsonStringify({
  49. cwd,
  50. ...(dangerouslySkipPermissions && {
  51. dangerously_skip_permissions: true,
  52. }),
  53. }),
  54. })
  55. } catch (err) {
  56. throw new DirectConnectError(
  57. `Failed to connect to server at ${serverUrl}: ${errorMessage(err)}`,
  58. )
  59. }
  60. if (!resp.ok) {
  61. throw new DirectConnectError(
  62. `Failed to create session: ${resp.status} ${resp.statusText}`,
  63. )
  64. }
  65. const result = connectResponseSchema().safeParse(await resp.json())
  66. if (!result.success) {
  67. throw new DirectConnectError(
  68. `Invalid session response: ${result.error.message}`,
  69. )
  70. }
  71. const data = result.data
  72. return {
  73. config: {
  74. serverUrl,
  75. sessionId: data.session_id,
  76. wsUrl: data.ws_url,
  77. authToken,
  78. },
  79. workDir: data.work_dir,
  80. }
  81. }