Summary
apiFetch in client/src/lib/api.ts (lines 14–21) merges its options like this:
const response = await fetch(`${API_BASE}${path}`, {
headers: { "Content-Type": "application/json", ...options?.headers },
...options, // ← spreads AFTER, so options.headers replaces the merged headers
});
Because ...options comes after the headers key, any caller that passes options.headers will have their headers completely replace the merged object — including the default Content-Type: application/json.
Impact
No current call site passes options.headers, so this is latent. But the next contributor to add e.g. an Authorization header on a POST will silently strip the JSON content type and hit a hard-to-diagnose 415 from the manager. This is a footgun waiting to fire.
Suggested fix
Reverse the spread order (or destructure explicitly):
const { headers: overrideHeaders, ...rest } = options ?? {};
const response = await fetch(`${API_BASE}${path}`, {
...rest,
headers: { "Content-Type": "application/json", ...overrideHeaders },
});
Summary
apiFetchinclient/src/lib/api.ts(lines 14–21) merges its options like this:Because
...optionscomes after theheaderskey, any caller that passesoptions.headerswill have their headers completely replace the merged object — including the defaultContent-Type: application/json.Impact
No current call site passes
options.headers, so this is latent. But the next contributor to add e.g. anAuthorizationheader on a POST will silently strip the JSON content type and hit a hard-to-diagnose 415 from the manager. This is a footgun waiting to fire.Suggested fix
Reverse the spread order (or destructure explicitly):