Files
pn-new-crm/src/lib/api/client.ts

46 lines
1.2 KiB
TypeScript
Raw Normal View History

'use client';
import { useUIStore } from '@/stores/ui-store';
export interface ApiFetchOptions extends Omit<RequestInit, 'body'> {
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<T = unknown>(
url: string,
opts: ApiFetchOptions = {},
): Promise<T> {
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<T>;
}