- Added an audit trail feature that logs every create, update, and delete action on delivery notes and orders, capturing detailed changes per field. - Introduced the `AuditTimeline` component to display the history of changes for delivery notes and orders, enhancing traceability. - Updated the `page.tsx` files for delivery notes and orders to fetch and display audit logs, ensuring users can view the history of modifications. - Enhanced the `package.json` with a new migration script for setting up the audit log functionality. This feature improves accountability and transparency in the management of delivery notes and orders.
41 lines
1.6 KiB
TypeScript
41 lines
1.6 KiB
TypeScript
/**
|
|
* Client-side: tag every same-origin `/api/` fetch with the logged-in
|
|
* user's PB token (as `x-wfdash-auth`) so the server can attribute the
|
|
* PocketBase writes it makes on their behalf in the audit trail.
|
|
*
|
|
* Many dashboard calls don't send `Authorization`, so without this the
|
|
* server only knows "someone" clicked. The token is verified by PB in
|
|
* the `audit_log` hook — it's attribution only, not route auth. The
|
|
* header name matches `AUDIT_AUTH_REQUEST_HEADER` in
|
|
* src/lib/server/audit-context.ts.
|
|
*/
|
|
const AUDIT_AUTH_HEADER = "x-wfdash-auth";
|
|
const INSTALLED = Symbol.for("wfdash.auditFetchInstalled");
|
|
|
|
function isSameOriginApi(input: RequestInfo | URL): boolean {
|
|
try {
|
|
const raw = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
const url = new URL(raw, window.location.origin);
|
|
return url.origin === window.location.origin && url.pathname.startsWith("/api/");
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function installAuditFetch(getToken: () => string): void {
|
|
if (typeof window === "undefined") return;
|
|
const w = window as unknown as Record<symbol, boolean>;
|
|
if (w[INSTALLED]) return;
|
|
w[INSTALLED] = true;
|
|
|
|
const original = window.fetch.bind(window);
|
|
window.fetch = (input: RequestInfo | URL, init?: RequestInit) => {
|
|
const token = getToken();
|
|
if (!token || !isSameOriginApi(input)) return original(input, init);
|
|
const headers = new Headers(
|
|
init?.headers ?? (input instanceof Request ? input.headers : undefined),
|
|
);
|
|
if (!headers.has(AUDIT_AUTH_HEADER)) headers.set(AUDIT_AUTH_HEADER, token);
|
|
return original(input, { ...init, headers });
|
|
};
|
|
}
|