Files
Raminder SinghandJoshen Lim 65237597e4 feat: upgrade flow and other improvements (#43289)
This PR:

* Adds an upgrade flow to the stripe sync engine, allowing users to
upgrade to the latest version when it becomes available.
* When a new version of sync engine becomes available, users will see an
upgrade button instead of install button.
* Bumps `supabase-management-js` to version 2.0.2 and
`stripe-experiment-sync` to version 1.0.27.
* Uses `parseSchemaComment` and related logic from the
`stripe-experiment-sync` package in order to avoid writing duplicate
code in supabase ui.
* Allows installation/uninstallation to timeout after 5 minutes to avoid
these operations from getting stuck in case an error occurs in their
processing. This allows users to retry the operation, as opposed to the
older behaviour where the users always see a spinner on the
install/uninstall button and couldn't do anything.
* Remove the SSL enforcement admonition as it is no longer required.
Sync engine can now be installed with or without SSL enforcement
enabled.

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
2026-03-18 08:29:03 +00:00

95 lines
2.5 KiB
TypeScript

import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
import { getAccessToken } from 'common'
import { databaseKeys } from 'data/database/keys'
import { BASE_PATH } from 'lib/constants'
import { useTrack } from 'lib/telemetry/track'
import { toast } from 'sonner'
import type { ResponseError } from 'types'
import { stripeSyncKeys } from './keys'
export type StripeSyncInstallVariables = {
projectRef: string
stripeSecretKey: string
startTime: number
}
export type StripeSyncInstallResponse = {
data: { message: string } | null
error: { message: string } | null
}
export async function installStripeSync({
projectRef,
stripeSecretKey,
startTime,
}: StripeSyncInstallVariables): Promise<StripeSyncInstallResponse> {
const accessToken = await getAccessToken()
const response = await fetch(`${BASE_PATH}/api/integrations/stripe-sync`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify({
projectRef,
stripeSecretKey,
startTime,
}),
})
const result = await response.json()
if (!response.ok) {
throw new Error(result.error?.message || 'Failed to install Stripe Sync')
}
return result
}
type StripeSyncInstallData = Awaited<ReturnType<typeof installStripeSync>>
export const useStripeSyncInstallMutation = ({
onSuccess,
onError,
...options
}: Omit<
UseMutationOptions<StripeSyncInstallData, ResponseError, StripeSyncInstallVariables>,
'mutationFn'
> = {}) => {
const queryClient = useQueryClient()
const track = useTrack()
return useMutation<StripeSyncInstallData, ResponseError, StripeSyncInstallVariables>({
mutationFn: (vars) => installStripeSync(vars),
async onSuccess(data, variables, context) {
const { projectRef } = variables
track('integration_install_submitted', {
integrationName: 'stripe_sync_engine',
})
// Invalidate schemas query to refresh installation status
await queryClient.invalidateQueries({
queryKey: databaseKeys.schemas(projectRef),
})
// Also invalidate any stripe sync related queries
await queryClient.invalidateQueries({
queryKey: stripeSyncKeys.all,
})
await onSuccess?.(data, variables, context)
},
async onError(data, variables, context) {
if (onError === undefined) {
toast.error(`Failed to install Stripe Sync: ${data.message}`)
} else {
onError(data, variables, context)
}
},
...options,
})
}