Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { getOrRefreshTemporaryApiKey } from '@/data/api-keys/temp-api-keys-utils'
import { handleError } from '@/data/fetchers'

/**
* Keeps the structural `custom:` prefix literal while still encoding the
* user-controlled slug, e.g. `custom:naver` -> `custom:naver`,
* `custom:my provider` -> `custom:my%20provider`.
*/
function encodeCustomProviderIdentifier(identifier: string) {
const slug = identifier.replace(/^custom:/i, '')
return `custom:${encodeURIComponent(slug)}`
}

function extractErrorMessage(payload: unknown, fallback: string) {
if (payload && typeof payload === 'object') {
if ('msg' in payload && typeof payload.msg === 'string') return payload.msg
if ('message' in payload && typeof payload.message === 'string') return payload.message
if ('error_description' in payload && typeof payload.error_description === 'string') {
return payload.error_description
}
}
return fallback
}

/**
* Performs a raw request against the GoTrue custom-providers admin endpoint.
*
* We bypass the auth-js SDK's `customProviders.updateProvider` / `deleteProvider`
* helpers here because they run the identifier through `encodeURIComponent`
* (supabase-js#2383), which turns the required `custom:` prefix into `custom%3A`.
* The GoTrue endpoint does not decode the path segment, so the encoded colon
* fails its `identifier must start with 'custom:'` validation.
*
* TODO: remove this and return to the SDK helpers once GoTrue decodes the
* custom-provider path segment (supabase-js#2383).
*/
export async function customProviderAdminRequest({
method,
projectRef,
clientEndpoint,
identifier,
body,
}: {
method: 'PUT' | 'DELETE'
projectRef: string
clientEndpoint: string
identifier: string
body?: unknown
}) {
const { apiKey } = await getOrRefreshTemporaryApiKey(projectRef)
const path = encodeCustomProviderIdentifier(identifier)

const response = await fetch(`${clientEndpoint}/auth/v1/admin/custom-providers/${path}`, {
method,
headers: {
apikey: apiKey,
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
})

if (!response.ok) {
let payload: unknown
try {
payload = await response.json()
} catch {
// response had no JSON body
}
handleError({
message: extractErrorMessage(payload, `Request failed with status ${response.status}`),
code: response.status,
})
}

if (method === 'DELETE') return null

try {
return await response.json()
} catch {
return null
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'

import { customProviderAdminRequest } from './custom-provider-admin-request'
import { oAuthCustomProvidersKeys } from './keys'
import { handleError } from '@/data/fetchers'
import { createProjectSupabaseClient } from '@/lib/project-supabase-client'
import type { ResponseError, UseCustomMutationOptions } from '@/types'

export type OAuthCustomProviderDeleteVariables = {
Expand All @@ -21,10 +20,12 @@ export async function deleteOAuthCustomProvider({
if (!clientEndpoint) throw new Error('Client endpoint is required')
if (!identifier) throw new Error('Provider identifier is required')

const supabaseClient = await createProjectSupabaseClient(projectRef, clientEndpoint)
const { error } = await supabaseClient.auth.admin.customProviders.deleteProvider(identifier)

if (error) handleError(error)
await customProviderAdminRequest({
method: 'DELETE',
projectRef,
clientEndpoint,
identifier,
})
return null
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ import type { UpdateCustomProviderParams } from '@supabase/auth-js'
import { useMutation, useQueryClient } from '@tanstack/react-query'
import { toast } from 'sonner'

import { customProviderAdminRequest } from './custom-provider-admin-request'
import { oAuthCustomProvidersKeys } from './keys'
import { handleError } from '@/data/fetchers'
import { createProjectSupabaseClient } from '@/lib/project-supabase-client'
import type { ResponseError, UseCustomMutationOptions } from '@/types'

export type OAuthCustomProviderUpdateVariables = UpdateCustomProviderParams & {
Expand All @@ -23,14 +22,13 @@ export async function updateOAuthCustomProvider({
if (!clientEndpoint) throw new Error('Client endpoint is required')
if (!identifier) throw new Error('Provider identifier is required')

const supabaseClient = await createProjectSupabaseClient(projectRef, clientEndpoint)
const { data, error } = await supabaseClient.auth.admin.customProviders.updateProvider(
return customProviderAdminRequest({
method: 'PUT',
projectRef,
clientEndpoint,
identifier,
params
)

if (error) handleError(error)
return data!
body: params,
})
}

type OAuthCustomProviderUpdateData = Awaited<ReturnType<typeof updateOAuthCustomProvider>>
Expand Down
6 changes: 0 additions & 6 deletions apps/www/components/Hero/Hero.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import SectionContainer from '~/components/Layouts/SectionContainer'
import { useSendTelemetryEvent } from '~/lib/telemetry'
import AnnouncementBadge from 'components/Announcement/Badge'
import Link from 'next/link'
import { Button } from 'ui'

Expand All @@ -14,11 +13,6 @@ const Hero = () => {
<div className="mx-auto">
<div className="mx-auto max-w-2xl lg:col-span-6 lg:flex lg:items-center justify-center text-center">
<div className="relative z-10 lg:h-auto pt-[90px] lg:pt-[90px] lg:min-h-[300px] flex flex-col items-center justify-center sm:mx-auto md:w-3/4 lg:mx-0 lg:w-full gap-4 lg:gap-8">
<AnnouncementBadge
url="/state-of-startups"
announcement="State of Startups 2026: Take the survey."
/>

<div className="flex flex-col items-center">
<h1 className="text-foreground text-4xl sm:text-5xl sm:leading-none lg:text-7xl">
<span className="block text-foreground">Build in a weekend</span>
Expand Down
Loading