Files
supabase/apps/studio/data/integrations/github-authorization-create-mutation.ts
Ali Waseem 1c2d28d5b3 chore: wrap local storage into helper methods that are safer (#46628)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

- Noticing our code we have many patterns of calling localstorage and
handling those errors
- We should add those in a single well tested file
- Handle those errors in the singleton which makes it easier for us to
debug customer issues. Logger is outputing local storage warnings for
feature we expose
- Side effect of this is random crashes on studio when local storage
isn't available or handled correctly

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Refactor**
* Improved browser storage handling across the app for more reliable
persistence and graceful behavior in restricted or non-browser
environments (settings, previews, charts, tabs, sign-in/session flows,
integrations, and UI state).

* **New Features**
* Introduced a safe storage layer to standardize and harden
local/session persistence.

* **Tests**
  * Added comprehensive tests covering the new safe storage behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-06-04 07:41:28 -06:00

76 lines
2.1 KiB
TypeScript

import { useMutation, useQueryClient } from '@tanstack/react-query'
import { LOCAL_STORAGE_KEYS, safeLocalStorage } from 'common'
import { toast } from 'sonner'
import { integrationKeys } from './keys'
import { handleError, post } from '@/data/fetchers'
import type { ResponseError, UseCustomMutationOptions } from '@/types'
export type GitHubAuthorizationCreateVariables = {
code: string
state: string
}
export async function createGitHubAuthorization({
code,
state,
}: GitHubAuthorizationCreateVariables) {
const localState = safeLocalStorage.getItem(LOCAL_STORAGE_KEYS.GITHUB_AUTHORIZATION_STATE)
if (state !== localState) {
throw new Error('GitHub authorization state mismatch')
} else {
safeLocalStorage.removeItem(LOCAL_STORAGE_KEYS.GITHUB_AUTHORIZATION_STATE)
}
const { data, error } = await post('/platform/integrations/github/authorization', {
body: { code },
})
if (error) handleError(error)
return data
}
type GitHubAuthorizationCreateData = Awaited<ReturnType<typeof createGitHubAuthorization>>
export const useGitHubAuthorizationCreateMutation = ({
onSuccess,
onError,
...options
}: Omit<
UseCustomMutationOptions<
GitHubAuthorizationCreateData,
ResponseError,
GitHubAuthorizationCreateVariables
>,
'mutationFn'
> = {}) => {
const queryClient = useQueryClient()
return useMutation<
GitHubAuthorizationCreateData,
ResponseError,
GitHubAuthorizationCreateVariables
>({
mutationFn: (vars) => createGitHubAuthorization(vars),
async onSuccess(data, variables, context) {
await Promise.all([
queryClient.invalidateQueries({
queryKey: integrationKeys.githubAuthorization(),
}),
queryClient.invalidateQueries({
queryKey: integrationKeys.githubRepositoriesList(),
}),
])
await onSuccess?.(data, variables, context)
},
async onError(data, variables, context) {
if (onError === undefined) {
toast.error(`Failed to mutate: ${data.message}`)
} else {
onError(data, variables, context)
}
},
...options,
})
}