(req: IncomingMessage, res: ServerResponse)
| 13193 | |
| 13194 | const paneTargetLockDir = projectDir ? getLocalDir(projectDir) : null; |
| 13195 | async function handleApiConfig(req: IncomingMessage, res: ServerResponse): Promise<void> { |
| 13196 | if (req.method === 'DELETE') { |
| 13197 | const peerAddress = req.socket?.remoteAddress; |
| 13198 | if (peerAddress !== undefined && !isLoopbackAddress(peerAddress)) { |
| 13199 | errorResponse(res, 403, 'urn:ok:error:loopback-required', 'Loopback required.', { |
| 13200 | handler: 'api-config', |
| 13201 | }); |
| 13202 | return; |
| 13203 | } |
| 13204 | if (!isAllowedWorkspaceHostHeader(req.headers.host)) { |
| 13205 | errorResponse(res, 403, 'urn:ok:error:host-not-allowed', 'Host header not allowed.', { |
| 13206 | handler: 'api-config', |
| 13207 | }); |
| 13208 | return; |
| 13209 | } |
| 13210 | if (paneTargetLockDir) clearArmedPaneTarget(paneTargetLockDir); |
| 13211 | res.setHeader('Cache-Control', 'no-store'); |
| 13212 | res.statusCode = 204; |
| 13213 | res.end(); |
| 13214 | return; |
| 13215 | } |
| 13216 | if (req.method === 'GET' || req.method === 'HEAD') { |
| 13217 | try { |
| 13218 | const host = req.headers.host; |
| 13219 | const collabUrl = host ? `ws://${host}/collab` : null; |
| 13220 | const port = paneTargetLockDir ? (readServerLock(paneTargetLockDir)?.port ?? 0) : 0; |
| 13221 | const paneTarget = paneTargetLockDir ? readArmedPaneTarget(paneTargetLockDir) : null; |
| 13222 | const payload = { collabUrl, previewUrl: null, port, paneTarget, singleFile: ephemeral }; |
| 13223 | if (req.method === 'HEAD') { |
| 13224 | res.setHeader('Content-Type', 'application/json'); |
| 13225 | res.setHeader('Cache-Control', 'no-store'); |
| 13226 | res.setHeader('X-Content-Type-Options', 'nosniff'); |
| 13227 | res.statusCode = 200; |
| 13228 | res.end(); |
| 13229 | return; |
| 13230 | } |
| 13231 | successResponse(res, 200, ApiConfigSuccessSchema, payload, { |
| 13232 | handler: 'api-config', |
| 13233 | extraHeaders: { 'Cache-Control': 'no-store' }, |
| 13234 | }); |
| 13235 | } catch (e) { |
| 13236 | errorResponse(res, 500, 'urn:ok:error:internal-server-error', 'Internal server error.', { |
| 13237 | handler: 'api-config', |
| 13238 | cause: e, |
| 13239 | }); |
| 13240 | } |
| 13241 | return; |
| 13242 | } |
| 13243 | errorResponse(res, 405, 'urn:ok:error:method-not-allowed', 'Method not allowed.', { |
| 13244 | handler: 'api-config', |
| 13245 | extraHeaders: { Allow: 'GET, HEAD, DELETE' }, |
| 13246 | }); |
| 13247 | } |
| 13248 | |
| 13249 | const HANDLE_LOCAL_OP_EMBEDDINGS_SET_KEY = 'local-op-embeddings-set-key'; |
| 13250 | const HANDLE_LOCAL_OP_EMBEDDINGS_CLEAR_KEY = 'local-op-embeddings-clear-key'; |
nothing calls this directly
no test coverage detected