'use client'; import { useUIStore } from '@/stores/ui-store'; export interface ApiFetchOptions extends Omit { body?: unknown; } /** * Client-side fetch wrapper that attaches the `X-Port-Id` header from the * UI store to every request. Used by all queryFn/mutationFn callbacks. */ export async function apiFetch( url: string, opts: ApiFetchOptions = {}, ): Promise { const portId = useUIStore.getState().currentPortId; const headers = new Headers(opts.headers); if (portId) { headers.set('X-Port-Id', portId); } if (opts.body !== undefined && !headers.has('Content-Type')) { headers.set('Content-Type', 'application/json'); } const res = await fetch(url, { ...opts, headers, credentials: 'include', body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined, }); if (!res.ok) { const error = await res.json().catch(() => ({ error: res.statusText })); throw Object.assign(new Error(error.error ?? 'Request failed'), { status: res.status, code: error.code, details: error.details, }); } if (res.status === 204) return undefined as T; return res.json() as Promise; }