()
| 61 | } |
| 62 | |
| 63 | async start(): Promise<string> { |
| 64 | if (!this.teamToken) { |
| 65 | throw new Error("team token is required to start hub mode"); |
| 66 | } |
| 67 | if (this.server?.listening) { |
| 68 | return `http://127.0.0.1:${this.port}`; |
| 69 | } |
| 70 | |
| 71 | this.server = http.createServer(async (req, res) => { |
| 72 | try { |
| 73 | await this.handle(req, res); |
| 74 | } catch (err: any) { |
| 75 | const code = err?.statusCode ?? 500; |
| 76 | const message = code === 413 ? "request_body_too_large" : "internal_error"; |
| 77 | this.opts.log.warn(`hub server error: ${String(err)}`); |
| 78 | res.statusCode = code; |
| 79 | res.setHeader("content-type", "application/json"); |
| 80 | res.end(JSON.stringify({ error: message })); |
| 81 | } |
| 82 | }); |
| 83 | |
| 84 | const MAX_PORT_RETRIES = 3; |
| 85 | let hubPort = this.port; |
| 86 | await new Promise<void>((resolve, reject) => { |
| 87 | let retries = 0; |
| 88 | const onError = (err: NodeJS.ErrnoException) => { |
| 89 | if (err.code === "EADDRINUSE" && retries < MAX_PORT_RETRIES) { |
| 90 | retries++; |
| 91 | hubPort = this.port + retries; |
| 92 | this.opts.log.warn(`Hub port ${hubPort - 1} in use, trying ${hubPort}`); |
| 93 | this.server!.listen(hubPort, "0.0.0.0"); |
| 94 | } else { |
| 95 | this.server?.off("listening", onListening); |
| 96 | reject(err); |
| 97 | } |
| 98 | }; |
| 99 | const onListening = () => { |
| 100 | this.server?.off("error", onError); |
| 101 | if (hubPort !== this.port) { |
| 102 | this.opts.log.info(`Hub started on fallback port ${hubPort} (configured: ${this.port})`); |
| 103 | } |
| 104 | resolve(); |
| 105 | }; |
| 106 | this.server!.on("error", onError); |
| 107 | this.server!.once("listening", onListening); |
| 108 | this.server!.listen(hubPort, "0.0.0.0"); |
| 109 | }); |
| 110 | |
| 111 | const bootstrap = this.userManager.ensureBootstrapAdmin( |
| 112 | this.authSecret, |
| 113 | "admin", |
| 114 | this.authState.bootstrapAdminUserId, |
| 115 | this.authState.bootstrapAdminToken, |
| 116 | ); |
| 117 | if (bootstrap.token) { |
| 118 | this.authState.bootstrapAdminUserId = bootstrap.user.id; |
| 119 | this.authState.bootstrapAdminToken = bootstrap.token; |
| 120 | this.saveAuthState(); |
nothing calls this directly
no test coverage detected