fix(git): make post-mutation status refresh authoritative (#2281)
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
co-authored by
Serhii Dziupin
parent
fe331c093b
commit
696349d606
@@ -37,6 +37,7 @@ import type {
|
||||
import { runtimeFetch } from './runtime-fetch';
|
||||
import { getRuntimeUrlResolver } from './runtime-url';
|
||||
import { getRuntimeKey } from './runtime-switch';
|
||||
import { notifyGitStatusInvalidated } from './gitStatusInvalidation';
|
||||
|
||||
const API_BASE = '/api/git';
|
||||
const GIT_STATUS_CACHE_TTL_MS = 1200;
|
||||
@@ -65,6 +66,16 @@ const invalidateGitStatusCache = (directory: string): void => {
|
||||
gitStatusCache.delete(statusKey);
|
||||
gitStatusInFlight.delete(statusKey);
|
||||
}
|
||||
notifyGitStatusInvalidated(directory);
|
||||
};
|
||||
|
||||
// Shared success path for status-affecting mutations. The payload is parsed
|
||||
// before invalidating so a failed mutation (non-ok response handled by the
|
||||
// caller, or a malformed body) cannot publish a false state change.
|
||||
const completeStatusMutation = async <T>(directory: string, response: Response): Promise<T> => {
|
||||
const result = await response.json() as T;
|
||||
invalidateGitStatusCache(directory);
|
||||
return result;
|
||||
};
|
||||
|
||||
function buildUrl(
|
||||
@@ -418,7 +429,7 @@ export async function deleteGitBranch(directory: string, payload: GitDeleteBranc
|
||||
throw new Error(error.error || 'Failed to delete branch');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function deleteRemoteBranch(directory: string, payload: GitDeleteRemoteBranchPayload): Promise<{ success: boolean }> {
|
||||
@@ -437,7 +448,7 @@ export async function deleteRemoteBranch(directory: string, payload: GitDeleteRe
|
||||
throw new Error(error.error || 'Failed to delete remote branch');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function removeRemote(directory: string, payload: GitRemoveRemotePayload): Promise<{ success: boolean }> {
|
||||
@@ -457,7 +468,7 @@ export async function removeRemote(directory: string, payload: GitRemoveRemotePa
|
||||
throw new Error(error.error || 'Failed to remove remote');
|
||||
}
|
||||
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function generateCommitMessage(
|
||||
@@ -664,9 +675,7 @@ export async function createGitCommit(
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to create commit');
|
||||
}
|
||||
const result = await response.json();
|
||||
invalidateGitStatusCache(directory);
|
||||
return result;
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function gitPush(
|
||||
@@ -682,9 +691,7 @@ export async function gitPush(
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to push');
|
||||
}
|
||||
const result = await response.json();
|
||||
invalidateGitStatusCache(directory);
|
||||
return result;
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function gitPull(
|
||||
@@ -700,9 +707,7 @@ export async function gitPull(
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to pull');
|
||||
}
|
||||
const result = await response.json();
|
||||
invalidateGitStatusCache(directory);
|
||||
return result;
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function gitFetch(
|
||||
@@ -718,9 +723,7 @@ export async function gitFetch(
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to fetch');
|
||||
}
|
||||
const result = await response.json();
|
||||
invalidateGitStatusCache(directory);
|
||||
return result;
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function listGitStashes(directory: string): Promise<{ stashes: GitStashEntry[] }> {
|
||||
@@ -755,7 +758,7 @@ export async function stashGitChanges(directory: string, options: { message?: st
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to stash changes');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
const postStashRef = async (directory: string, path: string, options: { ref: string }): Promise<{ success: boolean; ref: string }> => {
|
||||
@@ -768,7 +771,7 @@ const postStashRef = async (directory: string, path: string, options: { ref: str
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || `Failed to ${path}`);
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
};
|
||||
|
||||
export const applyGitStash = (directory: string, options: { ref: string }) => postStashRef(directory, 'stash/apply', options);
|
||||
@@ -785,7 +788,7 @@ export async function checkoutBranch(directory: string, branch: string): Promise
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to checkout branch');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function createBranch(
|
||||
@@ -802,7 +805,7 @@ export async function createBranch(
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to create branch');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function renameBranch(
|
||||
@@ -819,7 +822,7 @@ export async function renameBranch(
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to rename branch');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function getGitLog(
|
||||
@@ -1022,7 +1025,7 @@ export async function rebase(
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to rebase');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function abortRebase(directory: string): Promise<{ success: boolean }> {
|
||||
@@ -1033,7 +1036,7 @@ export async function abortRebase(directory: string): Promise<{ success: boolean
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to abort rebase');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function merge(
|
||||
@@ -1049,7 +1052,7 @@ export async function merge(
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to merge');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function checkoutCommit(
|
||||
@@ -1065,7 +1068,7 @@ export async function checkoutCommit(
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to checkout commit');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function cherryPick(
|
||||
@@ -1081,7 +1084,7 @@ export async function cherryPick(
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to cherry-pick');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function revertCommit(
|
||||
@@ -1097,7 +1100,7 @@ export async function revertCommit(
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to revert commit');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function resetToCommit(
|
||||
@@ -1115,7 +1118,7 @@ export async function resetToCommit(
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to reset');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function abortMerge(directory: string): Promise<{ success: boolean }> {
|
||||
@@ -1126,7 +1129,7 @@ export async function abortMerge(directory: string): Promise<{ success: boolean
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to abort merge');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function continueRebase(directory: string): Promise<{ success: boolean; conflict: boolean; conflictFiles?: string[] }> {
|
||||
@@ -1137,7 +1140,7 @@ export async function continueRebase(directory: string): Promise<{ success: bool
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to continue rebase');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function continueMerge(directory: string): Promise<{ success: boolean; conflict: boolean; conflictFiles?: string[] }> {
|
||||
@@ -1148,7 +1151,7 @@ export async function continueMerge(directory: string): Promise<{ success: boole
|
||||
const error = await response.json().catch(() => ({ error: response.statusText }));
|
||||
throw new Error(error.error || 'Failed to continue merge');
|
||||
}
|
||||
return response.json();
|
||||
return completeStatusMutation(directory, response);
|
||||
}
|
||||
|
||||
export async function stash(
|
||||
|
||||
Reference in New Issue
Block a user