fix(vcs): surface invalid installation tokens instead of empty results - #3147
fix(vcs): surface invalid installation tokens instead of empty results#3147HarshMN2345 wants to merge 2 commits into
Conversation
A VCS installation whose OAuth token can no longer be refreshed made every repository, branch and contents call fail with general_provider_failure. None of the Git surfaces read that error, so the console presented the failure as a successful empty result: repositories.svelte rendered its empty state, the branch selectors reported "No branches available", selectRootModal spun forever, and both updateRepository cards fell back to their "no repository connected" state for a repository that is in fact still connected. Classify the failure and render what actually happened, with the action that fixes it. Three kinds, because the remediation differs: - reconnect: the token is dead, only re-authorizing helps - locked: a concurrent refresh holds the lock, retrying works - provider: the provider itself failed, retry first general_provider_failure covers both a dead token and a provider outage, so the message is the only discriminator the API gives us. If that copy is ever reworded this degrades to the provider branch, which still shows a real error and still offers a reconnect. The repository cards gain an explicit fourth state rather than overloading the existing null sentinel, which already means "no repository connected" and is precisely the state being confused today. createGitDeploymentModal and createGit are migrated to runes, per AGENTS.md, since they had to be touched.
Greptile SummaryThe PR classifies installation-level VCS failures and surfaces actionable retry or reconnect states instead of misleading empty repository, branch, and directory views.
Confidence Score: 4/5The PR does not yet appear safe to merge because stale branch responses and retained repository rows can still cross repository or installation boundaries. Branch requests still commit results without checking the current repository key, and unclassified repository-list failures preserve cached rows without verifying that they belong to the selected installation; both previously reported state-isolation failures therefore remain reachable. Files Needing Attention: src/lib/components/git/branchSelector.svelte; src/lib/components/git/repositories.svelte Important Files Changed
Reviews (2): Last reviewed commit: "refactor(vcs): trim comments to this rep..." | Re-trigger Greptile |
vcsError.ts carried 43 lines of comment over 14 lines of code, saying the same thing in three overlapping blocks; the git components it sits beside average close to none. Kept only what is not inferable from the code: why the message substring is the discriminator, where that backend copy lives, and why the cast is structural rather than instanceof. installationError.svelte's header repeated the same context again. Same-directory imports of installationError were written two ways across the files this touched. Now all relative, matching connectGit.svelte.
57db238 to
d055808
Compare
Problem
When a VCS installation's OAuth token can no longer be refreshed, the API fails every repository / branch / contents call with
general_provider_failure(Appwrite\Vcs\InstallationTokens). None of the Git surfaces read that error, so a dead installation was presented as a successful empty result:repositories.svelteloadRepositories()had notry/catchat all, so the empty state claimed the org has no repositories. Used by 7 call sitesbranchSelector.svelte,productionBranchFieldset.svelteselectRootModal.svelteupdateRepository.sveltecardsconnectRepoModal, the create-deployment modalsChange
src/lib/helpers/vcsError.tsclassifies the failure into three kinds, because the remediation genuinely differs:reconnect- the token is dead, only re-authorizing helpslocked(general_resource_locked) - a concurrent refresh holds the lock, retrying works. Deliberately never offers a reconnect: the installation is fineprovider- the provider itself failed, retry first, reconnect demoted to secondarysrc/lib/components/git/installationError.svelterenders all three withAlert.Inlineand the reconnect link from the existing$lib/stores/githelpers. Reconnecting is a redirect to the existing authorize URL; the callback upserts the same installation row, so it is repaired in place.Notable details:
nullsentinel, which already means "no repository connected" and is exactly the state being confused today.createGitDeploymentModal.svelteand(modals)/createGit.svelteare migrated Svelte 4 -> runes, per AGENTS.md, since they had to be touched. The{#await load()}in both was replaced with an explicit effect-driven load, which also avoids the runes hazard where{#await}re-evaluates when a signal read inside it changes.Notes for review
general_provider_failurecovers both a dead token and a genuine provider outage; only the backend's "Please reconnect it." wording separates them. If reworded, this degrades to theproviderbranch, which still shows a real error and still offers a reconnect.$lib/stores/gitexportsconnectGitHubandconnectGiteabut noconnectGitLab, so the CTA is scoped to the providers the store supports.listInstallationsnever refreshes tokens, so a broken installation still looks healthy in the installations table until you use it.Unrelated backend finding, noted in passing
Not a blocker for this PR, and not introduced by it. Recording it for whoever owns VCS.
In
appwrite,GitHub/Callback/Get.phpinitialises the token variables tonulland only fills them insideif (!empty($code)), then writes them over the stored credentials unconditionally on the update path.codeis an optional param defaulting to''and is never checked before that write, and the three token attributes arerequired => false, default => nullinplatform.php, so a null write succeeds silently rather than erroring. It then fails quietly afterwards, becauseisExpired(null)returnsfalse.If GitHub can return a callback with
installation_idand nocode(an App without "Request user authorization (OAuth) during installation", or asetup_action=updaterepository-access reconfigure), that blanks working credentials. That is a GitHub behaviour I have not verified, so treat the reachability as unconfirmed.Worth stressing: this is reachable today through the existing "Configure" / "check your permissions" links, which use the same authorize and callback flow. This PR adds another entry point to it, it does not create it. GitLab and Gitea are unaffected, since their callback requires a
code.Verification
bun run check: 0 errors, 87 warnings - byte-identical to the baseline onmainvitest src/lib/helpers/vcsError.test.ts: 7/7 passeslintandprettier --checkclean on every changed file