import { createTRPCClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from '@zero/server/trpc';
import { getRuntimeBackendUrl } from '@/lib/runtime-urls';
import { createDeepDebuggerLink } from '@/modules/debugger/deepDebugger/trpcLink';
import { attachTraceIdToRecent } from '@/modules/debugger/deepDebugger/buffer';
import superjson from 'superjson';
let batchCounter = 0;
function nextBatchId(): string {
batchCounter++;
return `batch_${Date.now().toString(36)}_${batchCounter.toString(36)}`;
}
const getUrl = () => getRuntimeBackendUrl() + '/api/trpc';
export const api = createTRPCClient<AppRouter>({
links: [
createDeepDebuggerLink<AppRouter>(),
httpBatchLink({
url: getUrl(),
transformer: superjson,
headers: () => {
const headers: Record<string, string> = {};
if (typeof window !== 'undefined') {
const isPlaygroundRoute = window.location.pathname.includes('/playground');
if (isPlaygroundRoute) {
headers['X-From-Playground'] = 'true';
} else {
try {
const adminViewingUserId = sessionStorage.getItem('admin-viewing-user-id');
if (adminViewingUserId) {
headers['X-Admin-View-User'] = adminViewingUserId;
}
} catch {
// Ignore localStorage errors
}
}
}
return headers;
},
fetch: (url, options) => {
const batchId = nextBatchId();
const headers = new Headers(options?.headers);
headers.set('X-Client-Request-Id', batchId);
return fetch(url, { ...options, headers, credentials: 'include' }).then((res) => {
if (typeof window !== 'undefined') {
const currentPath = new URL(window.location.href).pathname;
const redirectPath = res.headers.get('X-Zero-Redirect');
if (!!redirectPath && redirectPath !== currentPath) {
window.location.href = redirectPath;
res.headers.delete('X-Zero-Redirect');
}
const traceId = res.headers.get('X-Trace-ID') ?? undefined;
const serverRequestId = res.headers.get('X-Request-ID') ?? undefined;
if (traceId || serverRequestId) {
attachTraceIdToRecent({ traceId, serverRequestId });
}
}
return res;
});
},
}),
],
});