(config: Config, opts: RequestOpts)
| 19 | } |
| 20 | |
| 21 | export async function request(config: Config, opts: RequestOpts): Promise<Response> { |
| 22 | const isFormData = typeof FormData !== 'undefined' && opts.body instanceof FormData; |
| 23 | |
| 24 | const headers: Record<string, string> = { |
| 25 | 'User-Agent': `mmx-cli/${CLI_VERSION}`, |
| 26 | ...opts.headers, |
| 27 | }; |
| 28 | |
| 29 | if (!isFormData && !headers['Content-Type']) { |
| 30 | headers['Content-Type'] = 'application/json'; |
| 31 | } |
| 32 | |
| 33 | if (!opts.noAuth) { |
| 34 | const credential = await resolveCredential(config); |
| 35 | |
| 36 | if (opts.authStyle === 'x-api-key') { |
| 37 | headers['x-api-key'] = credential.token; |
| 38 | } else { |
| 39 | headers['Authorization'] = `Bearer ${credential.token}`; |
| 40 | } |
| 41 | |
| 42 | if (config.verbose) { |
| 43 | process.stderr.write(`> ${opts.method ?? 'GET'} ${opts.url}\n`); |
| 44 | process.stderr.write(`> Auth: ${credential.token.slice(0, 8)}...\n`); |
| 45 | } |
| 46 | |
| 47 | const model = |
| 48 | opts.body && typeof opts.body === 'object' && 'model' in opts.body |
| 49 | ? String((opts.body as Record<string, unknown>).model) |
| 50 | : undefined; |
| 51 | |
| 52 | maybeShowStatusBar(config, credential.token, model); |
| 53 | } |
| 54 | |
| 55 | const timeoutMs = (opts.timeout ?? config.timeout) * 1000; |
| 56 | |
| 57 | const res = await fetch(opts.url, { |
| 58 | method: opts.method ?? 'GET', |
| 59 | headers, |
| 60 | body: opts.body |
| 61 | ? isFormData |
| 62 | ? (opts.body as FormData) |
| 63 | : JSON.stringify(opts.body) |
| 64 | : undefined, |
| 65 | signal: opts.stream ? undefined : AbortSignal.timeout(timeoutMs), |
| 66 | }); |
| 67 | |
| 68 | if (config.verbose) { |
| 69 | process.stderr.write(`< ${res.status} ${res.statusText}\n`); |
| 70 | } |
| 71 | |
| 72 | if (!res.ok) { |
| 73 | let body: ApiErrorBody = {}; |
| 74 | try { body = (await res.json()) as ApiErrorBody; } catch { /* non-JSON */ } |
| 75 | throw mapApiError(res.status, body, opts.url); |
| 76 | } |
| 77 | |
| 78 | return res; |
no test coverage detected