109 lines
3.4 KiB
TypeScript
109 lines
3.4 KiB
TypeScript
import type {
|
|
ChangeReport,
|
|
DiffResult,
|
|
DocumentVersion,
|
|
PatchContentBody,
|
|
RevisionState,
|
|
} from '../features/documentRevision/types';
|
|
import { mergeAuthHeaders } from './authHeaders';
|
|
|
|
async function api<T>(path: string, init?: RequestInit): Promise<T> {
|
|
const extra =
|
|
init?.headers instanceof Headers
|
|
? Object.fromEntries(init.headers.entries())
|
|
: ((init?.headers as Record<string, string> | undefined) ?? {});
|
|
const contentType =
|
|
typeof extra['Content-Type'] === 'string' ? extra['Content-Type'] : 'application/json';
|
|
const headers = mergeAuthHeaders(extra, contentType);
|
|
const res = await fetch(path, {
|
|
credentials: 'include',
|
|
...init,
|
|
headers,
|
|
});
|
|
const data = await res.json().catch(() => ({}));
|
|
if (!res.ok) {
|
|
const err = new Error((data as { error?: string }).error || res.statusText) as Error & {
|
|
status: number;
|
|
code?: string;
|
|
conflict?: unknown;
|
|
body?: unknown;
|
|
};
|
|
err.status = res.status;
|
|
err.code = (data as { code?: string }).code;
|
|
err.conflict = (data as { conflict?: unknown }).conflict;
|
|
err.body = data;
|
|
throw err;
|
|
}
|
|
return data as T;
|
|
}
|
|
|
|
export function getRevisionState(docId: string) {
|
|
return api<RevisionState>(`/api/v1/documents/${encodeURIComponent(docId)}/revision-state`);
|
|
}
|
|
|
|
export function listVersions(docId: string) {
|
|
return api<{ versions: DocumentVersion[] }>(`/api/v1/documents/${encodeURIComponent(docId)}/versions`);
|
|
}
|
|
|
|
export function getVersionContent(docId: string, versionNo: number, view: 'final' | 'baseline' = 'final') {
|
|
return api<{ content_markdown: string; content_sha256: string }>(
|
|
`/api/v1/documents/${encodeURIComponent(docId)}/versions/${versionNo}?view=${view}`,
|
|
);
|
|
}
|
|
|
|
export function getDiff(docId: string, fromVersion: number, toVersion: number) {
|
|
return api<DiffResult>(
|
|
`/api/v1/documents/${encodeURIComponent(docId)}/diff?from_version=${fromVersion}&to_version=${toVersion}&from_view=final&to_view=final`,
|
|
);
|
|
}
|
|
|
|
export function getManualOverlay(docId: string) {
|
|
return api<DiffResult>(`/api/v1/documents/${encodeURIComponent(docId)}/manual-overlay`);
|
|
}
|
|
|
|
export function patchDocumentContent(
|
|
docId: string,
|
|
body: PatchContentBody,
|
|
opts: { etag: string; idempotencyKey: string },
|
|
) {
|
|
return api<{ state: RevisionState; manual_overlay: DiffResult; conflict?: unknown }>(
|
|
`/api/v1/documents/${encodeURIComponent(docId)}/content`,
|
|
{
|
|
method: 'PATCH',
|
|
headers: {
|
|
'If-Match': `"${opts.etag}"`,
|
|
'Idempotency-Key': opts.idempotencyKey,
|
|
},
|
|
body: JSON.stringify(body),
|
|
},
|
|
);
|
|
}
|
|
|
|
export function getChangeReport(docId: string, reportId: number) {
|
|
return api<ChangeReport>(`/api/v1/documents/${encodeURIComponent(docId)}/change-reports/${reportId}`);
|
|
}
|
|
|
|
export function decideAgentCandidate(
|
|
docId: string,
|
|
candidateId: number,
|
|
body: {
|
|
decision: 'commit' | 'reject';
|
|
confirmed?: boolean;
|
|
expected_input_sha?: string;
|
|
expected_output_sha?: string;
|
|
reason?: string;
|
|
},
|
|
) {
|
|
return api<RevisionState>(
|
|
`/api/v1/documents/${encodeURIComponent(docId)}/agent-candidates/${candidateId}/decision`,
|
|
{ method: 'POST', body: JSON.stringify(body) },
|
|
);
|
|
}
|
|
|
|
export function patchNotification(id: number, status: 'read' | 'acted' | 'dismissed') {
|
|
return api<{ ok: boolean }>(`/api/v1/notifications/${id}`, {
|
|
method: 'PATCH',
|
|
body: JSON.stringify({ status }),
|
|
});
|
|
}
|